{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sentiment Classification of Movie Reviews (using Naive Bayes, Logistic Regression, and Ngrams)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The purpose of this notebook is to cover Naive Bayes, Logistic regression, and ngrams (some pretty classic techniques!) for sentiment classification.  We will be using sklearn and the fastai library.\n",
    "\n",
    "In a future lesson, we will tackle this same problem of sentiment classification using deep learning, so that you can compare the two approaches"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The content here was extended from [Lesson 10 of the fast.ai Machine Learning course](https://course.fast.ai/lessonsml1/lesson10.html). Linear model is pretty close to the state of the art here.  Jeremy surpassed state of the art using a RNN in fall 2017."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## The fastai library"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "hidden": true
   },
   "source": [
    "We will begin using [the fastai library](https://docs.fast.ai) (version 1.0) in this notebook.  We will use it more once we move on to neural networks.\n",
    "\n",
    "The fastai library is built on top of PyTorch and encodes many state-of-the-art best practices. It is used in production at a number of companies.  You can read more about it here:\n",
    "\n",
    "- [Fast.ai's software could radically democratize AI](https://www.zdnet.com/article/fast-ais-new-software-could-radically-democratize-ai/) (ZDNet)\n",
    "\n",
    "- [fastai v1 for PyTorch: Fast and accurate neural nets using modern best practices](https://www.fast.ai/2018/10/02/fastai-ai/) (fast.ai)\n",
    "\n",
    "- [fastai docs](https://docs.fast.ai/)\n",
    "\n",
    "### Installation\n",
    "\n",
    "With conda:\n",
    "\n",
    "`conda install -c pytorch -c fastai fastai=1.0`\n",
    "\n",
    "Or with pip:\n",
    "\n",
    "`pip install fastai==1.0`\n",
    "\n",
    "More [installation information here](https://github.com/fastai/fastai/blob/master/README.md).\n",
    "\n",
    "Beginning in lesson 4, we will be using GPUs, so if you want, you could switch to a [cloud option](https://course.fast.ai/#using-a-gpu) now to setup fastai."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## IMDB dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The [large movie review dataset](http://ai.stanford.edu/~amaas/data/sentiment/) contains a collection of 50,000 reviews from IMDB, We will use the version hosted as part [fast.ai datasets](https://course.fast.ai/datasets.html) on AWS Open Datasets. \n",
    "\n",
    "The dataset contains an even number of positive and negative reviews. The authors considered only highly polarized reviews. A negative review has a score ≤ 4 out of 10, and a positive review has a score ≥ 7 out of 10. Neutral reviews are not included in the dataset. The dataset is divided into training and test sets. The training set is the same 25,000 labeled reviews.\n",
    "\n",
    "The **sentiment classification task** consists of predicting the polarity (positive or negative) of a given text."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "%reload_ext autoreload\n",
    "%autoreload 2\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from fastai import *\n",
    "from fastai.text import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sklearn.feature_extraction.text as sklearn_text"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tokenizing and term document matrix creation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "fast.ai has a number of [datasets hosted via AWS Open Datasets](https://course.fast.ai/datasets.html) for easy download. We can see them by checking the docs for URLs (remember `??` is a helpful command):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 273,
   "metadata": {},
   "outputs": [],
   "source": [
    "?? URLs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is always good to start working on a sample of your data before you use the full dataset-- this allows for quicker computations as you debug and get your code working. For IMDB, there is a sample dataset already available:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PosixPath('/home/racheltho/.fastai/data/imdb_sample')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "path = untar_data(URLs.IMDB_SAMPLE)\n",
    "path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are not going to use this dataframe, but are just loading it to get a sense of what our data looks like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>text</th>\n",
       "      <th>is_valid</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>negative</td>\n",
       "      <td>Un-bleeping-believable! Meg Ryan doesn't even ...</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>positive</td>\n",
       "      <td>This is a extremely well-made film. The acting...</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>negative</td>\n",
       "      <td>Every once in a long while a movie will come a...</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>positive</td>\n",
       "      <td>Name just says it all. I watched this movie wi...</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>negative</td>\n",
       "      <td>This movie succeeds at being one of the most u...</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      label                                               text  is_valid\n",
       "0  negative  Un-bleeping-believable! Meg Ryan doesn't even ...     False\n",
       "1  positive  This is a extremely well-made film. The acting...     False\n",
       "2  negative  Every once in a long while a movie will come a...     False\n",
       "3  positive  Name just says it all. I watched this movie wi...     False\n",
       "4  negative  This movie succeeds at being one of the most u...     False"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv(path/'texts.csv')\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will be using [TextList](https://docs.fast.ai/text.data.html#TextList) from the fastai library:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "movie_reviews = (TextList.from_csv(path, 'texts.csv', cols='text')\n",
    "                         .split_from_df(col=2)\n",
    "                         .label_from_df(cols=0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exploring what our data looks like"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A good first step for any data problem is to explore the data and get a sense of what it looks like.  In this case we are looking at movie reviews, which have been labeled as \"positive\" or \"negative\":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Text xxbos xxmaj this very funny xxmaj british comedy shows what might happen if a section of xxmaj london , in this case xxmaj xxunk , were to xxunk itself independent from the rest of the xxup uk and its laws , xxunk & post - war xxunk . xxmaj merry xxunk is what would happen . \n",
       "  \n",
       "   xxmaj the explosion of a wartime bomb leads to the xxunk of ancient xxunk which show that xxmaj xxunk was xxunk to the xxmaj xxunk of xxmaj xxunk xxunk ago , a small historical xxunk long since forgotten . xxmaj to the new xxmaj xxunk , however , this is an unexpected opportunity to live as they please , free from any xxunk from xxmaj xxunk . \n",
       "  \n",
       "   xxmaj stanley xxmaj xxunk is excellent as the minor city xxunk who suddenly finds himself leading one of the world 's xxunk xxunk . xxmaj xxunk xxmaj margaret xxmaj xxunk is a delight as the history professor who sides with xxmaj xxunk . xxmaj others in the stand - out cast include xxmaj xxunk xxmaj xxunk , xxmaj paul xxmaj xxunk , xxmaj xxunk xxmaj xxunk , xxmaj xxunk xxmaj xxunk & xxmaj sir xxmaj michael xxmaj xxunk . \n",
       "  \n",
       "   xxmaj welcome to xxmaj xxunk !, Category positive)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.valid.x[0], movie_reviews.valid.y[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In NLP, a **token** is the basic unit of processing (what the tokens are depends on the application and your choices). Here, the tokens mostly correspond to words or punctuation, as well as several special tokens, corresponding to unknown words, capitalization, etc."
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "iVBORw0KGgoAAAANSUhEUgAAA08AAAHMCAYAAAANhZNFAAAgAElEQVR4Aey9D1Bb553v/d3XqfyuZ+l4BiaZla87VpqNGPe17CzSeI0cbyBswc4CTgtKaohbBJ0AvgvEU+PcNea2gGcNTmPBXAN9g5UpFmkseBtEbwxMHUhdi10iZm3Lt74obxJ5mmvd1x4067FaOqhmzjvPkY50dHQEh7+G+KcZW0fPeZ7f8/t9nv9/+QuO4zjQhwgQASJABIgAESACRIAIEAEiQATmJPB/zPmWXhIBIkAEiAARIAJEgAgQASJABIgAT4AGT5QRiAARIAJEgAgQASJABIgAESACCgjQ4EkBJPJCBIgAESACRIAIEAEiQASIABGgwRPlASJABIgAESACRIAIEAEiQASIgAICNHhSAIm8EAEiQASIABEgAkSACBABIkAEaPBEeYAIEAEiQASIABEgAkSACBABIqCAAA2eFEAiL0SACBABIkAEiAARIAJEgAgQARo8UR4gAkSACBABIkAEiAARIAJEgAgoIECDJwWQyAsRIAJEgAgQASJABIgAESACRIAGT5QHiAARIAJEgAgQASJABIgAESACCgjQ4EkBJPJCBIgAESACRIAIEAEiQASIABGgwRPlASJABIgAESACRIAIEAEiQASIgAICNHhSAIm8EAEiQASIABEgAkSACBABIkAEaPBEeYAIEAEiQASIABEgAkSACBABIqCAAA2eFEAiL0SACBABIkAEiAARIAJEgAgQARo8UR4gAkSACBABIkAEiAARIAJEgAgoILCowZN/oBp6vV7Bv2o47gGCf8t1BRo9Ui9+OKr00Fc54H+keqzVyOP5hNI2lM4Jtb5u4fNKNP3j5SQMuwov3G0sL1vgniuuOBvm8qzsnSJ2ykQto69w2szHYxljXLSoew5U6/WoHlih0hpO8xWTv2jD11DAlU6D5TLVN4KWkoxwm1WNIcVZxg0La+se9zZh0em8OnW9ojp8ufISySECROCxJ/DEYgiovmGEuUwrCurDRNcQ3DtyYN6tFrmnQPOXop/0SASWQmA2AK+zF44/5aMmO3kpkigsEYglQHkrlsdX6pcfjtO1sH+ug/lUBQybv46nN8sb6L9uR/utVJw8pJP3QK4rRoDYrxhaEkwEiMAyE1jU4ClplwmVu8SauGFhg6fnTKgsj290FE/yiUXS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xW1pJO924MJb1bBNhzjWvnscph0JJiuXPS/JsddgKWmsLToJ84dmWBuakalnfxNNeVshl0RybtqSHvSq29Hxcweaj1oRZHnw2b0wnepFZXaiCUs5SeRGBIjAeiLwF+yu9fWkMOlKBIjAYgl4YT/ciy1dtbQPf7EIKdzKE2BnPQ80AjRLH8daWMEo7ppADVslow8RIAJEgAisOoG1deZp1c2nCInA40MgeN2B3g3boFmpFcTHByVZugwE3G0ZKDxig0d8DpWd9XSys54qaL4hXs5dhghJBBEgAkSACBCBZSCw5rbtLYNNJIIIEIE4AkHcuOJF/rHKubd/xoUjByKwMgRSMwqBbgvKq6b4M4TqjUH4xm2wdLug2teE12hlZWXAk1QiQASIABFYEgEaPC0JHwUmAuuFgAqGqlbEHjtfL7qTnl9FAqodlejs/DrOvuuA5aiNvxWNnW/dX9+Dipe0kj8I8FUkQDYRASJABIjAeiRAZ57WY6qRzkSACBABIkAEiAARIAJEgAisOgE687TqyClCIkAEiAARIAJEgAgQASJABNYjARo8rcdUI52JABEgAkSACBABIkAEiAARWHUCNHhadeQUIREgAkSACBABIkAEiAARIALrkQANntZjqpHORIAIEAEiQASIABEgAkSACKw6ARo8rTpyipAIEAEiQASIABEgAkSACBCB9UiABk/rMdVIZyJABIgAESACRIAIEAEiQARWnQANnlYdOUVIBIgAESACRIAIEAEiQASIwHokQIOn9ZhqpDMRIAJEgAgQASJABIgAESACq06ABk+rjpwiJAJEgAgQASJABIgAESACRGA9EqDB03pMNdKZCBABIkAEiAARIAJEgAgQgVUnQIOnVUdOERIBIkAEiAARIAJEgAgQASKwHgnQ4Gk9phrpTASIABEgAkSACBABIkAEiMCqE6DB06ojpwiJABEgAkSACBABIkAEiAARWI8EaPC0HlONdCYCRIAIEAEiQASIABEgAkRg1QnQ4GnVkVOERIAIEAEiQASIABEgAkSACKxHAk+sR6WXW+eHDx/iz3/+M2ZnZ5dbtCJ5GzZswNe+9jU88QQlhyJg5IkIEAEiQASIABEgAkSACDwCAn/BcRz3COJdM1HOzMzwA6e1oBAbQG3cuHEtqEI6EAEiQASIABEgAkSACBABIiAh8Fhv2xNWnCRMHtlP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dlRm1CGh9WNUps5g5ikitdALvt5y/hfmjR1DqJjSA0hoWgp53Am4YNaZYCnsxBCbtV2yn8elHEvWAFMrzvd31cCRATRlymfEp05IV4kAESACRGAhCSzJPU8LCWyhZWtzS5F+ywI7cxX+mH28l63oTyxGTsr8DpweM2xUnBkS4AfQe5vQL3iEE7MJDPXz3hoNifxuCjF40X4/LuVYtIDnSTHPJSv6V+UjL40GTvOEmLIlAkSACMwLgSW752kuaKxYsQLj49JdtnOR6+zyYDpN+VmdhX0HTqGgy468MD9COWXaxXwx4IK1axj5b52EdhoEi7kYpNvSIRD/1zuw/u1qVJfeF/bHAT5h356XeaTMCvFpuSgL97iUY1HCnXOlPLAf78PtwC2cO+9C0qEa4bed5lwQZUgEiAARIALzRGBZD56efPLJRTd4YjpN99EWNqD0pUM4dSMdFZsfj1kazwdm9G9vwfl5Xq43HVu6vowIrMnCsfeAtpOncfpICXwP2A8Ya7G1sB2tRXqF+/JFzOVxKcciRjx3qn0b+NqCzssrkZTbhIZcyc80zJ0QyokIEAEiQATmkcCy3vPEuI6NjeGbb76ZR8TRZ80GTivZD33ShwgQASJABIgAESACRIAIEIFFR2DZD56YRR4+fMgPoBZqCR9bqscGTk88sawnAhdd4yCFiAARIAJEgAgQASJABIiAlAANnqQ06JgIEAEiQASIABEgAkSACBABIhCBAHnbiwCGgokAESACRIAIEAEiQASIABEgAlICNHiS0qBjIkAEiAARIAJEgAgQASJABIhABAI0eIoAhoKJABEgAkSACBABIkAEiAARIAJSAjR4ktKgYyJABIgAESACRIAIEAEiQASIQAQCNHiKAIaCiQARIAJEgAgQASJABIgAESACUgI0eJLSoGMiQASIABEgAkSACBABIkAEiEAEAjR4igCGgokAESACRIAIEAEiQASIABEgAlICNHiS0qBjIkAEiAARIAJEgAgQASJABIhABAI0eIoAhoKJABEgAkSACBABIkAEiAARIAJSAjR4ktKgYyJABIgAESACRIAIEAEiQASIQAQCNHiKAIaCiQARIAJEgAgQASJABIgAESACUgI0eJLSoGMiQASIABEgAkSACBABIkAEiEAEAjR4igCGgokAESACRIAIEAEiQASIABEgAlICT0hPluvx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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All those tokens starting with \"xx\" are fastai special tokens.  You can see the list of all of them and their meanings ([in the fastai docs](https://docs.fast.ai/text.transform.html)): \n",
    "\n",
    "![image.png](attachment:image.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(800, 200)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(movie_reviews.train.x), len(movie_reviews.valid.x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that ints-to-string and string-to-ints have different lengths.  Think for a moment about why this is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(6016, 19160)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(movie_reviews.vocab.itos), len(movie_reviews.vocab.stoi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "917"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.stoi['language']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'language'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[917]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['that', 'this', '\"', \"'s\", '\\n \\n ', '-', 'was', 'as', 'for', 'movie']"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[20:30]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'sollett'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[6009]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['xxunk',\n",
       " 'xxpad',\n",
       " 'xxbos',\n",
       " 'xxeos',\n",
       " 'xxfld',\n",
       " 'xxmaj',\n",
       " 'xxup',\n",
       " 'xxrep',\n",
       " 'xxwrep',\n",
       " 'the',\n",
       " '.',\n",
       " ',',\n",
       " 'and',\n",
       " 'a',\n",
       " 'of',\n",
       " 'to',\n",
       " 'is',\n",
       " 'it',\n",
       " 'in',\n",
       " 'i']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[:20]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "defaultdict(int,\n",
       "            {'xxunk': 0,\n",
       "             'xxpad': 1,\n",
       "             'xxbos': 2,\n",
       "             'xxeos': 3,\n",
       "             'xxfld': 4,\n",
       "             'xxmaj': 5,\n",
       "             'xxup': 6,\n",
       "             'xxrep': 7,\n",
       "             'xxwrep': 8,\n",
       "             'the': 9,\n",
       "             '.': 10,\n",
       "             ',': 11,\n",
       "             'and': 12,\n",
       "             'a': 13,\n",
       "             'of': 14,\n",
       "             'to': 15,\n",
       "             'is': 16,\n",
       "             'it': 17,\n",
       "             'in': 18,\n",
       "             'i': 19,\n",
       "             'that': 20,\n",
       "             'this': 21,\n",
       "             '\"': 22,\n",
       "             \"'s\": 23,\n",
       "             '\\n \\n ': 24,\n",
       "             '-': 25,\n",
       "             'was': 26,\n",
       "             'as': 27,\n",
       "             'for': 28,\n",
       "             'movie': 29,\n",
       "             'with': 30,\n",
       "             'but': 31,\n",
       "             'film': 32,\n",
       "             'you': 33,\n",
       "             ')': 34,\n",
       "             'on': 35,\n",
       "             '(': 36,\n",
       "             \"n't\": 37,\n",
       "             'are': 38,\n",
       "             'he': 39,\n",
       "             'his': 40,\n",
       "             'not': 41,\n",
       "             'have': 42,\n",
       "             'be': 43,\n",
       "             'one': 44,\n",
       "             'they': 45,\n",
       "             'all': 46,\n",
       "             'at': 47,\n",
       "             'by': 48,\n",
       "             'an': 49,\n",
       "             'from': 50,\n",
       "             'like': 51,\n",
       "             '!': 52,\n",
       "             'so': 53,\n",
       "             'who': 54,\n",
       "             'there': 55,\n",
       "             'about': 56,\n",
       "             'just': 57,\n",
       "             'out': 58,\n",
       "             'if': 59,\n",
       "             'or': 60,\n",
       "             'do': 61,\n",
       "             'what': 62,\n",
       "             'her': 63,\n",
       "             'has': 64,\n",
       "             \"'\": 65,\n",
       "             'some': 66,\n",
       "             'more': 67,\n",
       "             'good': 68,\n",
       "             'when': 69,\n",
       "             'up': 70,\n",
       "             'very': 71,\n",
       "             '?': 72,\n",
       "             'she': 73,\n",
       "             'would': 74,\n",
       "             'no': 75,\n",
       "             'really': 76,\n",
       "             'were': 77,\n",
       "             'their': 78,\n",
       "             'my': 79,\n",
       "             'had': 80,\n",
       "             'time': 81,\n",
       "             'can': 82,\n",
       "             'only': 83,\n",
       "             'which': 84,\n",
       "             'even': 85,\n",
       "             'see': 86,\n",
       "             'story': 87,\n",
       "             'me': 88,\n",
       "             'into': 89,\n",
       "             'did': 90,\n",
       "             ':': 91,\n",
       "             'well': 92,\n",
       "             'we': 93,\n",
       "             'will': 94,\n",
       "             'does': 95,\n",
       "             'than': 96,\n",
       "             'also': 97,\n",
       "             'get': 98,\n",
       "             '...': 99,\n",
       "             'people': 100,\n",
       "             'other': 101,\n",
       "             'bad': 102,\n",
       "             'been': 103,\n",
       "             'could': 104,\n",
       "             'first': 105,\n",
       "             'much': 106,\n",
       "             'how': 107,\n",
       "             'most': 108,\n",
       "             'any': 109,\n",
       "             'because': 110,\n",
       "             'two': 111,\n",
       "             'then': 112,\n",
       "             'great': 113,\n",
       "             'him': 114,\n",
       "             'its': 115,\n",
       "             'too': 116,\n",
       "             'made': 117,\n",
       "             'them': 118,\n",
       "             'after': 119,\n",
       "             'movies': 120,\n",
       "             'make': 121,\n",
       "             '/': 122,\n",
       "             'way': 123,\n",
       "             'think': 124,\n",
       "             'never': 125,\n",
       "             'watch': 126,\n",
       "             'acting': 127,\n",
       "             'seen': 128,\n",
       "             ';': 129,\n",
       "             'films': 130,\n",
       "             'plot': 131,\n",
       "             'being': 132,\n",
       "             'many': 133,\n",
       "             'over': 134,\n",
       "             'where': 135,\n",
       "             'character': 136,\n",
       "             'man': 137,\n",
       "             'little': 138,\n",
       "             'better': 139,\n",
       "             'life': 140,\n",
       "             'characters': 141,\n",
       "             'love': 142,\n",
       "             'your': 143,\n",
       "             'here': 144,\n",
       "             'know': 145,\n",
       "             'scenes': 146,\n",
       "             'best': 147,\n",
       "             'end': 148,\n",
       "             'show': 149,\n",
       "             'while': 150,\n",
       "             'through': 151,\n",
       "             'should': 152,\n",
       "             'off': 153,\n",
       "             'ever': 154,\n",
       "             'these': 155,\n",
       "             'go': 156,\n",
       "             'such': 157,\n",
       "             'say': 158,\n",
       "             '--': 159,\n",
       "             'something': 160,\n",
       "             'scene': 161,\n",
       "             'still': 162,\n",
       "             'before': 163,\n",
       "             'though': 164,\n",
       "             'watching': 165,\n",
       "             'between': 166,\n",
       "             'actually': 167,\n",
       "             'old': 168,\n",
       "             '10': 169,\n",
       "             'find': 170,\n",
       "             'back': 171,\n",
       "             'now': 172,\n",
       "             'why': 173,\n",
       "             'years': 174,\n",
       "             \"'ve\": 175,\n",
       "             'actors': 176,\n",
       "             'fact': 177,\n",
       "             'those': 178,\n",
       "             \"'m\": 179,\n",
       "             'thing': 180,\n",
       "             'pretty': 181,\n",
       "             'quite': 182,\n",
       "             'part': 183,\n",
       "             'going': 184,\n",
       "             'same': 185,\n",
       "             'real': 186,\n",
       "             'another': 187,\n",
       "             'down': 188,\n",
       "             'funny': 189,\n",
       "             'nothing': 190,\n",
       "             'look': 191,\n",
       "             'makes': 192,\n",
       "             '*': 193,\n",
       "             'new': 194,\n",
       "             'want': 195,\n",
       "             'action': 196,\n",
       "             '&': 197,\n",
       "             'director': 198,\n",
       "             'work': 199,\n",
       "             'few': 200,\n",
       "             \"'re\": 201,\n",
       "             'seems': 202,\n",
       "             'around': 203,\n",
       "             'world': 204,\n",
       "             'point': 205,\n",
       "             'without': 206,\n",
       "             'cast': 207,\n",
       "             'again': 208,\n",
       "             'own': 209,\n",
       "             'both': 210,\n",
       "             'lot': 211,\n",
       "             'enough': 212,\n",
       "             'every': 213,\n",
       "             'family': 214,\n",
       "             'got': 215,\n",
       "             'ca': 216,\n",
       "             \"'ll\": 217,\n",
       "             'probably': 218,\n",
       "             'big': 219,\n",
       "             'bit': 220,\n",
       "             'might': 221,\n",
       "             'things': 222,\n",
       "             'horror': 223,\n",
       "             'us': 224,\n",
       "             'almost': 225,\n",
       "             'may': 226,\n",
       "             'right': 227,\n",
       "             'must': 228,\n",
       "             'away': 229,\n",
       "             'thought': 230,\n",
       "             'interesting': 231,\n",
       "             'least': 232,\n",
       "             'whole': 233,\n",
       "             'series': 234,\n",
       "             'gets': 235,\n",
       "             'each': 236,\n",
       "             'give': 237,\n",
       "             'young': 238,\n",
       "             'however': 239,\n",
       "             'making': 240,\n",
       "             'day': 241,\n",
       "             'fun': 242,\n",
       "             'anything': 243,\n",
       "             'minutes': 244,\n",
       "             'kind': 245,\n",
       "             'come': 246,\n",
       "             'girl': 247,\n",
       "             'saw': 248,\n",
       "             'script': 249,\n",
       "             'take': 250,\n",
       "             'long': 251,\n",
       "             'times': 252,\n",
       "             'someone': 253,\n",
       "             'found': 254,\n",
       "             'done': 255,\n",
       "             'feel': 256,\n",
       "             'far': 257,\n",
       "             'since': 258,\n",
       "             'role': 259,\n",
       "             'original': 260,\n",
       "             'course': 261,\n",
       "             'goes': 262,\n",
       "             'last': 263,\n",
       "             'true': 264,\n",
       "             'simply': 265,\n",
       "             'always': 266,\n",
       "             \"'d\": 267,\n",
       "             'tv': 268,\n",
       "             'hard': 269,\n",
       "             'place': 270,\n",
       "             'set': 271,\n",
       "             'trying': 272,\n",
       "             'believe': 273,\n",
       "             'shot': 274,\n",
       "             'comes': 275,\n",
       "             'actor': 276,\n",
       "             'yet': 277,\n",
       "             '4': 278,\n",
       "             'having': 279,\n",
       "             'book': 280,\n",
       "             'looks': 281,\n",
       "             'guy': 282,\n",
       "             'screen': 283,\n",
       "             'later': 284,\n",
       "             'shows': 285,\n",
       "             'performance': 286,\n",
       "             'worth': 287,\n",
       "             'audience': 288,\n",
       "             'comedy': 289,\n",
       "             'sure': 290,\n",
       "             'looking': 291,\n",
       "             'sense': 292,\n",
       "             'star': 293,\n",
       "             'effects': 294,\n",
       "             'read': 295,\n",
       "             'takes': 296,\n",
       "             'although': 297,\n",
       "             'ending': 298,\n",
       "             'john': 299,\n",
       "             'anyone': 300,\n",
       "             'worst': 301,\n",
       "             'american': 302,\n",
       "             'year': 303,\n",
       "             'especially': 304,\n",
       "             'women': 305,\n",
       "             'together': 306,\n",
       "             'dvd': 307,\n",
       "             'instead': 308,\n",
       "             'different': 309,\n",
       "             'am': 310,\n",
       "             'woman': 311,\n",
       "             'men': 312,\n",
       "             '2': 313,\n",
       "             'our': 314,\n",
       "             'played': 315,\n",
       "             'music': 316,\n",
       "             'special': 317,\n",
       "             'three': 318,\n",
       "             'rest': 319,\n",
       "             'put': 320,\n",
       "             'maybe': 321,\n",
       "             'wife': 322,\n",
       "             'kids': 323,\n",
       "             'war': 324,\n",
       "             'left': 325,\n",
       "             'black': 326,\n",
       "             'once': 327,\n",
       "             'second': 328,\n",
       "             'watched': 329,\n",
       "             'next': 330,\n",
       "             'friends': 331,\n",
       "             'rather': 332,\n",
       "             'let': 333,\n",
       "             '\\x96': 334,\n",
       "             'job': 335,\n",
       "             'start': 336,\n",
       "             'others': 337,\n",
       "             'budget': 338,\n",
       "             'need': 339,\n",
       "             'mind': 340,\n",
       "             'said': 341,\n",
       "             'main': 342,\n",
       "             'else': 343,\n",
       "             'wrong': 344,\n",
       "             'beautiful': 345,\n",
       "             'half': 346,\n",
       "             'high': 347,\n",
       "             'idea': 348,\n",
       "             'death': 349,\n",
       "             'tell': 350,\n",
       "             'help': 351,\n",
       "             'nice': 352,\n",
       "             'seem': 353,\n",
       "             'perhaps': 354,\n",
       "             'hollywood': 355,\n",
       "             'everyone': 356,\n",
       "             'play': 357,\n",
       "             'case': 358,\n",
       "             'production': 359,\n",
       "             'piece': 360,\n",
       "             'episode': 361,\n",
       "             'camera': 362,\n",
       "             'low': 363,\n",
       "             'already': 364,\n",
       "             'top': 365,\n",
       "             'poor': 366,\n",
       "             'during': 367,\n",
       "             '3': 368,\n",
       "             'stars': 369,\n",
       "             'house': 370,\n",
       "             '..': 371,\n",
       "             'couple': 372,\n",
       "             'boring': 373,\n",
       "             'reason': 374,\n",
       "             'try': 375,\n",
       "             'along': 376,\n",
       "             'name': 377,\n",
       "             'small': 378,\n",
       "             'plays': 379,\n",
       "             'father': 380,\n",
       "             'everything': 381,\n",
       "             'used': 382,\n",
       "             'video': 383,\n",
       "             'getting': 384,\n",
       "             'money': 385,\n",
       "             'full': 386,\n",
       "             'less': 387,\n",
       "             'performances': 388,\n",
       "             'often': 389,\n",
       "             'liked': 390,\n",
       "             'came': 391,\n",
       "             '1': 392,\n",
       "             'robert': 393,\n",
       "             'either': 394,\n",
       "             'fan': 395,\n",
       "             'given': 396,\n",
       "             'hand': 397,\n",
       "             'kill': 398,\n",
       "             'felt': 399,\n",
       "             'yes': 400,\n",
       "             'completely': 401,\n",
       "             'night': 402,\n",
       "             'children': 403,\n",
       "             'himself': 404,\n",
       "             'girls': 405,\n",
       "             'early': 406,\n",
       "             'awful': 407,\n",
       "             'oh': 408,\n",
       "             'live': 409,\n",
       "             'picture': 410,\n",
       "             'parts': 411,\n",
       "             'throughout': 412,\n",
       "             'until': 413,\n",
       "             'become': 414,\n",
       "             'town': 415,\n",
       "             'written': 416,\n",
       "             'terrible': 417,\n",
       "             'turn': 418,\n",
       "             'child': 419,\n",
       "             'despite': 420,\n",
       "             'moments': 421,\n",
       "             'boy': 422,\n",
       "             'problem': 423,\n",
       "             'able': 424,\n",
       "             'head': 425,\n",
       "             'stupid': 426,\n",
       "             'beginning': 427,\n",
       "             'home': 428,\n",
       "             'version': 429,\n",
       "             'excellent': 430,\n",
       "             'sometimes': 431,\n",
       "             'overall': 432,\n",
       "             'recommend': 433,\n",
       "             'sex': 434,\n",
       "             'keep': 435,\n",
       "             'human': 436,\n",
       "             'drama': 437,\n",
       "             'hero': 438,\n",
       "             'supposed': 439,\n",
       "             'seemed': 440,\n",
       "             'use': 441,\n",
       "             'writing': 442,\n",
       "             'wo': 443,\n",
       "             'remember': 444,\n",
       "             'went': 445,\n",
       "             'enjoy': 446,\n",
       "             'classic': 447,\n",
       "             'person': 448,\n",
       "             'killer': 449,\n",
       "             'lost': 450,\n",
       "             'late': 451,\n",
       "             '5': 452,\n",
       "             'title': 453,\n",
       "             'king': 454,\n",
       "             'entire': 455,\n",
       "             'history': 456,\n",
       "             'son': 457,\n",
       "             'school': 458,\n",
       "             'lead': 459,\n",
       "             'english': 460,\n",
       "             'sound': 461,\n",
       "             'cinema': 462,\n",
       "             'seeing': 463,\n",
       "             'unfortunately': 464,\n",
       "             'genre': 465,\n",
       "             'sort': 466,\n",
       "             'mean': 467,\n",
       "             'friend': 468,\n",
       "             'fans': 469,\n",
       "             'close': 470,\n",
       "             'quality': 471,\n",
       "             'definitely': 472,\n",
       "             'james': 473,\n",
       "             'worse': 474,\n",
       "             'says': 475,\n",
       "             'except': 476,\n",
       "             'doing': 477,\n",
       "             'itself': 478,\n",
       "             'past': 479,\n",
       "             'certainly': 480,\n",
       "             'days': 481,\n",
       "             'five': 482,\n",
       "             'dialogue': 483,\n",
       "             'line': 484,\n",
       "             'anyway': 485,\n",
       "             'under': 486,\n",
       "             'tries': 487,\n",
       "             'called': 488,\n",
       "             'fine': 489,\n",
       "             'guys': 490,\n",
       "             'care': 491,\n",
       "             'style': 492,\n",
       "             'hope': 493,\n",
       "             'short': 494,\n",
       "             'lines': 495,\n",
       "             'told': 496,\n",
       "             'car': 497,\n",
       "             'decent': 498,\n",
       "             'brother': 499,\n",
       "             'killed': 500,\n",
       "             'wanted': 501,\n",
       "             'entertaining': 502,\n",
       "             'based': 503,\n",
       "             'absolutely': 504,\n",
       "             'feeling': 505,\n",
       "             'truly': 506,\n",
       "             'etc': 507,\n",
       "             'heard': 508,\n",
       "             'serious': 509,\n",
       "             'run': 510,\n",
       "             'wonderful': 511,\n",
       "             'lives': 512,\n",
       "             'gives': 513,\n",
       "             'moment': 514,\n",
       "             'game': 515,\n",
       "             'documentary': 516,\n",
       "             'self': 517,\n",
       "             'several': 518,\n",
       "             'waste': 519,\n",
       "             'dead': 520,\n",
       "             'blood': 521,\n",
       "             'matter': 522,\n",
       "             'wonder': 523,\n",
       "             'humor': 524,\n",
       "             'thinking': 525,\n",
       "             'against': 526,\n",
       "             'white': 527,\n",
       "             'side': 528,\n",
       "             'works': 529,\n",
       "             'mother': 530,\n",
       "             'flick': 531,\n",
       "             'stuff': 532,\n",
       "             'turns': 533,\n",
       "             'finally': 534,\n",
       "             'loved': 535,\n",
       "             'group': 536,\n",
       "             'wants': 537,\n",
       "             'face': 538,\n",
       "             'guess': 539,\n",
       "             'dark': 540,\n",
       "             'city': 541,\n",
       "             'events': 542,\n",
       "             'starts': 543,\n",
       "             'hour': 544,\n",
       "             'took': 545,\n",
       "             'george': 546,\n",
       "             'themselves': 547,\n",
       "             'red': 548,\n",
       "             'behind': 549,\n",
       "             'talking': 550,\n",
       "             'hit': 551,\n",
       "             'eyes': 552,\n",
       "             'attempt': 553,\n",
       "             'direction': 554,\n",
       "             'novel': 555,\n",
       "             'saying': 556,\n",
       "             'word': 557,\n",
       "             'dull': 558,\n",
       "             'light': 559,\n",
       "             'view': 560,\n",
       "             'playing': 561,\n",
       "             'opinion': 562,\n",
       "             'expect': 563,\n",
       "             'evil': 564,\n",
       "             'ten': 565,\n",
       "             'violence': 566,\n",
       "             'local': 567,\n",
       "             'final': 568,\n",
       "             'gave': 569,\n",
       "             'leave': 570,\n",
       "             'paul': 571,\n",
       "             'crap': 572,\n",
       "             'happens': 573,\n",
       "             'knows': 574,\n",
       "             'problems': 575,\n",
       "             'example': 576,\n",
       "             'relationship': 577,\n",
       "             'non': 578,\n",
       "             'michael': 579,\n",
       "             'victor': 580,\n",
       "             'ridiculous': 581,\n",
       "             'god': 582,\n",
       "             'similar': 583,\n",
       "             'general': 584,\n",
       "             'major': 585,\n",
       "             'bunch': 586,\n",
       "             'sister': 587,\n",
       "             'oscar': 588,\n",
       "             'turned': 589,\n",
       "             'brilliant': 590,\n",
       "             'highly': 591,\n",
       "             'nearly': 592,\n",
       "             'de': 593,\n",
       "             'please': 594,\n",
       "             'romance': 595,\n",
       "             'body': 596,\n",
       "             'extremely': 597,\n",
       "             'mr.': 598,\n",
       "             'soon': 599,\n",
       "             'yourself': 600,\n",
       "             'known': 601,\n",
       "             'lack': 602,\n",
       "             'age': 603,\n",
       "             'interest': 604,\n",
       "             'ago': 605,\n",
       "             'stories': 606,\n",
       "             'exactly': 607,\n",
       "             'finds': 608,\n",
       "             'modern': 609,\n",
       "             'voice': 610,\n",
       "             'perfect': 611,\n",
       "             'heart': 612,\n",
       "             'alone': 613,\n",
       "             'tells': 614,\n",
       "             'daughter': 615,\n",
       "             'directed': 616,\n",
       "             'needs': 617,\n",
       "             'kid': 618,\n",
       "             'lady': 619,\n",
       "             'sad': 620,\n",
       "             'fight': 621,\n",
       "             'happened': 622,\n",
       "             'eye': 623,\n",
       "             'favorite': 624,\n",
       "             'using': 625,\n",
       "             'upon': 626,\n",
       "             'ben': 627,\n",
       "             'none': 628,\n",
       "             'beyond': 629,\n",
       "             'nature': 630,\n",
       "             'change': 631,\n",
       "             'save': 632,\n",
       "             'shots': 633,\n",
       "             'country': 634,\n",
       "             'number': 635,\n",
       "             'shown': 636,\n",
       "             'surprised': 637,\n",
       "             'romantic': 638,\n",
       "             'huge': 639,\n",
       "             'murder': 640,\n",
       "             'steve': 641,\n",
       "             'slow': 642,\n",
       "             'myself': 643,\n",
       "             'woods': 644,\n",
       "             'apparently': 645,\n",
       "             'lake': 646,\n",
       "             'cheap': 647,\n",
       "             'involved': 648,\n",
       "             'roles': 649,\n",
       "             '6': 650,\n",
       "             'gore': 651,\n",
       "             'obviously': 652,\n",
       "             'knew': 653,\n",
       "             'level': 654,\n",
       "             '8': 655,\n",
       "             'experience': 656,\n",
       "             'became': 657,\n",
       "             'gone': 658,\n",
       "             'cover': 659,\n",
       "             'amazing': 660,\n",
       "             'create': 661,\n",
       "             'living': 662,\n",
       "             'usually': 663,\n",
       "             'order': 664,\n",
       "             'monster': 665,\n",
       "             'happen': 666,\n",
       "             'list': 667,\n",
       "             'clearly': 668,\n",
       "             'power': 669,\n",
       "             'features': 670,\n",
       "             're': 671,\n",
       "             'subject': 672,\n",
       "             'across': 673,\n",
       "             'parents': 674,\n",
       "             'seriously': 675,\n",
       "             'ways': 676,\n",
       "             'room': 677,\n",
       "             'filmed': 678,\n",
       "             'cheesy': 679,\n",
       "             'disappointed': 680,\n",
       "             'important': 681,\n",
       "             'plenty': 682,\n",
       "             '7': 683,\n",
       "             'particular': 684,\n",
       "             'started': 685,\n",
       "             'today': 686,\n",
       "             'enjoyed': 687,\n",
       "             'cinematography': 688,\n",
       "             'annoying': 689,\n",
       "             'looked': 690,\n",
       "             'supporting': 691,\n",
       "             'mostly': 692,\n",
       "             'message': 693,\n",
       "             'somewhat': 694,\n",
       "             'viewer': 695,\n",
       "             'type': 696,\n",
       "             'certain': 697,\n",
       "             'release': 698,\n",
       "             'effort': 699,\n",
       "             'possible': 700,\n",
       "             'add': 701,\n",
       "             'figure': 702,\n",
       "             'named': 703,\n",
       "             'wish': 704,\n",
       "             'difficult': 705,\n",
       "             'falls': 706,\n",
       "             'four': 707,\n",
       "             'husband': 708,\n",
       "             'score': 709,\n",
       "             'leads': 710,\n",
       "             'form': 711,\n",
       "             'working': 712,\n",
       "             'writer': 713,\n",
       "             'sets': 714,\n",
       "             'including': 715,\n",
       "             'enjoyable': 716,\n",
       "             'ok': 717,\n",
       "             'note': 718,\n",
       "             'spent': 719,\n",
       "             'review': 720,\n",
       "             'art': 721,\n",
       "             'police': 722,\n",
       "             'sit': 723,\n",
       "             'horrible': 724,\n",
       "             'actress': 725,\n",
       "             'ones': 726,\n",
       "             'bring': 727,\n",
       "             'greatest': 728,\n",
       "             'dance': 729,\n",
       "             'earth': 730,\n",
       "             'becomes': 731,\n",
       "             'happy': 732,\n",
       "             'cut': 733,\n",
       "             'straight': 734,\n",
       "             'soundtrack': 735,\n",
       "             'leading': 736,\n",
       "             'laugh': 737,\n",
       "             'strange': 738,\n",
       "             'space': 739,\n",
       "             'b': 740,\n",
       "             'tale': 741,\n",
       "             'comic': 742,\n",
       "             'near': 743,\n",
       "             'due': 744,\n",
       "             'weak': 745,\n",
       "             'earlier': 746,\n",
       "             'follow': 747,\n",
       "             'british': 748,\n",
       "             'ends': 749,\n",
       "             'typical': 750,\n",
       "             'attention': 751,\n",
       "             'points': 752,\n",
       "             'talent': 753,\n",
       "             'tom': 754,\n",
       "             'female': 755,\n",
       "             'future': 756,\n",
       "             'fall': 757,\n",
       "             'laughs': 758,\n",
       "             'stop': 759,\n",
       "             'easy': 760,\n",
       "             'moving': 761,\n",
       "             'apart': 762,\n",
       "             'chance': 763,\n",
       "             'running': 764,\n",
       "             'york': 765,\n",
       "             'particularly': 766,\n",
       "             'luke': 767,\n",
       "             'bill': 768,\n",
       "             'forced': 769,\n",
       "             'theme': 770,\n",
       "             'easily': 771,\n",
       "             'rating': 772,\n",
       "             'coming': 773,\n",
       "             'davis': 774,\n",
       "             'totally': 775,\n",
       "             'realistic': 776,\n",
       "             'simple': 777,\n",
       "             'hours': 778,\n",
       "             'taken': 779,\n",
       "             'indeed': 780,\n",
       "             'released': 781,\n",
       "             'sexual': 782,\n",
       "             'feels': 783,\n",
       "             'french': 784,\n",
       "             'screenplay': 785,\n",
       "             'la': 786,\n",
       "             'jokes': 787,\n",
       "             'sequences': 788,\n",
       "             'chase': 789,\n",
       "             'portrayed': 790,\n",
       "             'dramatic': 791,\n",
       "             'mention': 792,\n",
       "             'talk': 793,\n",
       "             'gun': 794,\n",
       "             'thriller': 795,\n",
       "             'jimmy': 796,\n",
       "             'career': 797,\n",
       "             'reality': 798,\n",
       "             'incredibly': 799,\n",
       "             'whether': 800,\n",
       "             'towards': 801,\n",
       "             'entertainment': 802,\n",
       "             'feature': 803,\n",
       "             'western': 804,\n",
       "             'dialog': 805,\n",
       "             'business': 806,\n",
       "             'suspense': 807,\n",
       "             'focus': 808,\n",
       "             'doubt': 809,\n",
       "             'possibly': 810,\n",
       "             'water': 811,\n",
       "             'gay': 812,\n",
       "             'blob': 813,\n",
       "             'comments': 814,\n",
       "             'brothers': 815,\n",
       "             'clear': 816,\n",
       "             'agree': 817,\n",
       "             'allen': 818,\n",
       "             'door': 819,\n",
       "             'editing': 820,\n",
       "             'third': 821,\n",
       "             'deserves': 822,\n",
       "             'silly': 823,\n",
       "             'fantastic': 824,\n",
       "             'convincing': 825,\n",
       "             'hardly': 826,\n",
       "             'lame': 827,\n",
       "             'act': 828,\n",
       "             'former': 829,\n",
       "             'material': 830,\n",
       "             'appears': 831,\n",
       "             'understand': 832,\n",
       "             'twist': 833,\n",
       "             'episodes': 834,\n",
       "             'buy': 835,\n",
       "             'secret': 836,\n",
       "             'richard': 837,\n",
       "             'south': 838,\n",
       "             'bourne': 839,\n",
       "             'deal': 840,\n",
       "             'musical': 841,\n",
       "             'words': 842,\n",
       "             'unique': 843,\n",
       "             'mess': 844,\n",
       "             'opening': 845,\n",
       "             'society': 846,\n",
       "             'avoid': 847,\n",
       "             'footage': 848,\n",
       "             'joe': 849,\n",
       "             'free': 850,\n",
       "             'forget': 851,\n",
       "             'herself': 852,\n",
       "             'appear': 853,\n",
       "             'obvious': 854,\n",
       "             'box': 855,\n",
       "             'single': 856,\n",
       "             'average': 857,\n",
       "             'indian': 858,\n",
       "             'rent': 859,\n",
       "             'okay': 860,\n",
       "             'scary': 861,\n",
       "             'within': 862,\n",
       "             'office': 863,\n",
       "             'crime': 864,\n",
       "             'science': 865,\n",
       "             '80': 866,\n",
       "             'believable': 867,\n",
       "             'period': 868,\n",
       "             'showing': 869,\n",
       "             'call': 870,\n",
       "             'return': 871,\n",
       "             'keeps': 872,\n",
       "             'lee': 873,\n",
       "             'expected': 874,\n",
       "             'stay': 875,\n",
       "             'middle': 876,\n",
       "             'jack': 877,\n",
       "             'hands': 878,\n",
       "             'david': 879,\n",
       "             'attempts': 880,\n",
       "             'strong': 881,\n",
       "             'tension': 882,\n",
       "             'crew': 883,\n",
       "             'hilarious': 884,\n",
       "             'grade': 885,\n",
       "             'outside': 886,\n",
       "             'means': 887,\n",
       "             'viewing': 888,\n",
       "             'sadly': 889,\n",
       "             'hell': 890,\n",
       "             'whatever': 891,\n",
       "             'sorry': 892,\n",
       "             'recently': 893,\n",
       "             'stage': 894,\n",
       "             'decides': 895,\n",
       "             'hear': 896,\n",
       "             'team': 897,\n",
       "             'learn': 898,\n",
       "             'nor': 899,\n",
       "             'open': 900,\n",
       "             'break': 901,\n",
       "             'question': 902,\n",
       "             'remake': 903,\n",
       "             'porn': 904,\n",
       "             'pain': 905,\n",
       "             'imagine': 906,\n",
       "             'deep': 907,\n",
       "             'zombie': 908,\n",
       "             'basically': 909,\n",
       "             'killing': 910,\n",
       "             'company': 911,\n",
       "             'poorly': 912,\n",
       "             'dr.': 913,\n",
       "             'predictable': 914,\n",
       "             'taking': 915,\n",
       "             'large': 916,\n",
       "             'language': 917,\n",
       "             'giving': 918,\n",
       "             'public': 919,\n",
       "             'audiences': 920,\n",
       "             'ask': 921,\n",
       "             'cool': 922,\n",
       "             'america': 923,\n",
       "             'slasher': 924,\n",
       "             'west': 925,\n",
       "             'mentioned': 926,\n",
       "             'die': 927,\n",
       "             'christmas': 928,\n",
       "             'complete': 929,\n",
       "             'needed': 930,\n",
       "             'martin': 931,\n",
       "             'makers': 932,\n",
       "             'cgi': 933,\n",
       "             'boys': 934,\n",
       "             'vargas': 935,\n",
       "             'usual': 936,\n",
       "             'begin': 937,\n",
       "             'dad': 938,\n",
       "             'total': 939,\n",
       "             'somehow': 940,\n",
       "             'stick': 941,\n",
       "             'shame': 942,\n",
       "             'successful': 943,\n",
       "             'sitting': 944,\n",
       "             'fred': 945,\n",
       "             'meets': 946,\n",
       "             'unless': 947,\n",
       "             'dancing': 948,\n",
       "             'sounds': 949,\n",
       "             'above': 950,\n",
       "             'elements': 951,\n",
       "             'whose': 952,\n",
       "             'german': 953,\n",
       "             'considering': 954,\n",
       "             'caught': 955,\n",
       "             'credit': 956,\n",
       "             'interested': 957,\n",
       "             'move': 958,\n",
       "             'filming': 959,\n",
       "             'truth': 960,\n",
       "             'eventually': 961,\n",
       "             'share': 962,\n",
       "             'ability': 963,\n",
       "             'meaning': 964,\n",
       "             'agent': 965,\n",
       "             'fast': 966,\n",
       "             'stand': 967,\n",
       "             'onto': 968,\n",
       "             'plain': 969,\n",
       "             'comment': 970,\n",
       "             'kept': 971,\n",
       "             'situation': 972,\n",
       "             'setting': 973,\n",
       "             'value': 974,\n",
       "             'willing': 975,\n",
       "             'realize': 976,\n",
       "             'acted': 977,\n",
       "             'weird': 978,\n",
       "             'alive': 979,\n",
       "             'fairly': 980,\n",
       "             'dream': 981,\n",
       "             'building': 982,\n",
       "             'hair': 983,\n",
       "             'bored': 984,\n",
       "             'minute': 985,\n",
       "             'emotional': 986,\n",
       "             'directing': 987,\n",
       "             'theatrical': 988,\n",
       "             'famous': 989,\n",
       "             'begins': 990,\n",
       "             'front': 991,\n",
       "             'catch': 992,\n",
       "             'sequence': 993,\n",
       "             'runs': 994,\n",
       "             'follows': 995,\n",
       "             'song': 996,\n",
       "             'government': 997,\n",
       "             'miss': 998,\n",
       "             'actual': 999,\n",
       "             ...})"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.stoi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's test that a non-word maps to xxunk:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'xxunk'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[movie_reviews.vocab.stoi['rrachell']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'language'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[movie_reviews.vocab.stoi['language']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = movie_reviews.train[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([   2,    5, 4622,   25,    0,   25,  867,   52,    5, 3776,    5, 1800,   95,   37,   85,  191,   63,  936,\n",
       "          0, 2740,  517,   18,   21,   11,   84, 2418,  192,   88, 3777,   63])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t.data[:30]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating our term-document matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we covered in the last lesson, a term-document matrix represents a document as a \"bag of words\", that is, we don't keep track of the order the words are in, just which words occur (and how often)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the previous lesson, we used [sklearn's CountVectorizer](https://github.com/scikit-learn/scikit-learn/blob/55bf5d9/sklearn/feature_extraction/text.py#L940).  Today we will create our own (similar) version.  This is for two reasons:\n",
    "- to understand what sklearn is doing underneath the hood\n",
    "- to create something that will work with a fastai TextList"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To create our term-document matrix, we first need to learn about **counters** and **sparse matrices**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Counters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Counters are a useful Python object.  If you aren't familar with them, here is how they work:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = Counter([4,2,8,8,4,8])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 248,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({4: 2, 2: 1, 8: 3})"
      ]
     },
     "execution_count": 248,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_values([2, 1, 3])"
      ]
     },
     "execution_count": 182,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c.values()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 183,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_keys([4, 2, 8])"
      ]
     },
     "execution_count": 183,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c.keys()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Counters are from the collections module (along with OrderedDict, defaultdict, deque, and namedtuple)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Sparse Matrices (in Scipy)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Even though we've reduced over 19,000 words down to 6,000, that is still a lot! Most tokens don't appear in most reviews.  We want to take advantage of this by storing our data as a **sparse matrix**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A matrix with lots of zeros is called **sparse** (the opposite of sparse is **dense**).  For sparse matrices, you can save a lot of memory by only storing the non-zero values.\n",
    "\n",
    "<img src=\"images/sparse.png\" alt=\"floating point\" style=\"width: 30%\"/>\n",
    "\n",
    "Another example of a large, sparse matrix:\n",
    "\n",
    "<img src=\"images/Finite_element_sparse_matrix.png\" alt=\"floating point\" style=\"width: 30%\"/>\n",
    "\n",
    "[Source](https://commons.wikimedia.org/w/index.php?curid=2245335)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are the most common sparse storage formats:\n",
    "- coordinate-wise (scipy calls COO)\n",
    "- compressed sparse row (CSR)\n",
    "- compressed sparse column (CSC)\n",
    "\n",
    "Let's walk through [these examples](http://www.mathcs.emory.edu/~cheung/Courses/561/Syllabus/3-C/sparse.html)\n",
    "\n",
    "There are actually [many more formats](http://www.cs.colostate.edu/~mcrob/toolbox/c++/sparseMatrix/sparse_matrix_compression.html) as well."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A class of matrices (e.g, diagonal) is generally called sparse if the number of non-zero elements is proportional to the number of rows (or columns) instead of being proportional to the product rows x columns.\n",
    "\n",
    "**Scipy Implementation**\n",
    "\n",
    "From the [Scipy Sparse Matrix Documentation](https://docs.scipy.org/doc/scipy-0.18.1/reference/sparse.html)\n",
    "\n",
    "- To construct a matrix efficiently, use either dok_matrix or lil_matrix. The lil_matrix class supports basic slicing and fancy indexing with a similar syntax to NumPy arrays. As illustrated below, the COO format may also be used to efficiently construct matrices\n",
    "- To perform manipulations such as multiplication or inversion, first convert the matrix to either CSC or CSR format.\n",
    "- All conversions among the CSR, CSC, and COO formats are efficient, linear-time operations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Our version of CountVectorizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 263,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({2: 1,\n",
       "         5: 32,\n",
       "         21: 3,\n",
       "         71: 1,\n",
       "         189: 1,\n",
       "         748: 1,\n",
       "         289: 1,\n",
       "         285: 1,\n",
       "         62: 2,\n",
       "         221: 1,\n",
       "         666: 2,\n",
       "         59: 1,\n",
       "         13: 4,\n",
       "         2707: 1,\n",
       "         14: 6,\n",
       "         2877: 1,\n",
       "         11: 10,\n",
       "         18: 2,\n",
       "         358: 1,\n",
       "         0: 32,\n",
       "         77: 1,\n",
       "         15: 6,\n",
       "         478: 1,\n",
       "         1833: 1,\n",
       "         50: 3,\n",
       "         9: 10,\n",
       "         319: 1,\n",
       "         6: 1,\n",
       "         2745: 1,\n",
       "         12: 1,\n",
       "         115: 1,\n",
       "         4129: 1,\n",
       "         197: 2,\n",
       "         1331: 1,\n",
       "         25: 2,\n",
       "         324: 1,\n",
       "         10: 7,\n",
       "         3963: 1,\n",
       "         16: 4,\n",
       "         74: 1,\n",
       "         24: 3,\n",
       "         2819: 1,\n",
       "         5823: 1,\n",
       "         2597: 1,\n",
       "         710: 1,\n",
       "         3430: 1,\n",
       "         84: 1,\n",
       "         149: 1,\n",
       "         20: 1,\n",
       "         26: 1,\n",
       "         605: 1,\n",
       "         378: 1,\n",
       "         1057: 1,\n",
       "         251: 1,\n",
       "         258: 1,\n",
       "         1346: 1,\n",
       "         194: 1,\n",
       "         239: 1,\n",
       "         49: 1,\n",
       "         2766: 1,\n",
       "         1335: 1,\n",
       "         409: 1,\n",
       "         27: 3,\n",
       "         45: 1,\n",
       "         594: 1,\n",
       "         850: 1,\n",
       "         109: 1,\n",
       "         2603: 1,\n",
       "         430: 1,\n",
       "         1902: 1,\n",
       "         541: 1,\n",
       "         54: 2,\n",
       "         1107: 1,\n",
       "         608: 1,\n",
       "         404: 1,\n",
       "         736: 1,\n",
       "         44: 1,\n",
       "         204: 1,\n",
       "         23: 1,\n",
       "         3481: 1,\n",
       "         4739: 1,\n",
       "         456: 1,\n",
       "         4053: 1,\n",
       "         2421: 1,\n",
       "         30: 1,\n",
       "         337: 1,\n",
       "         967: 1,\n",
       "         58: 1,\n",
       "         207: 1,\n",
       "         2110: 1,\n",
       "         571: 1,\n",
       "         5037: 1,\n",
       "         579: 1,\n",
       "         1843: 1,\n",
       "         52: 1})"
      ]
     },
     "execution_count": 263,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Counter((movie_reviews.valid.x)[0].data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'xxup'"
      ]
     },
     "execution_count": 264,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[6]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'movie_reviews' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m--------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m        Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-1fa92856acc1>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0mmovie_reviews\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m: name 'movie_reviews' is not defined"
     ]
    }
   ],
   "source": [
    "(movie_reviews.valid.x)[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 258,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text xxbos xxmaj this very funny xxmaj british comedy shows what might happen if a section of xxmaj london , in this case xxmaj xxunk , were to xxunk itself independent from the rest of the xxup uk and its laws , xxunk & post - war xxunk . xxmaj merry xxunk is what would happen . \n",
       " \n",
       "  xxmaj the explosion of a wartime bomb leads to the xxunk of ancient xxunk which show that xxmaj xxunk was xxunk to the xxmaj xxunk of xxmaj xxunk xxunk ago , a small historical xxunk long since forgotten . xxmaj to the new xxmaj xxunk , however , this is an unexpected opportunity to live as they please , free from any xxunk from xxmaj xxunk . \n",
       " \n",
       "  xxmaj stanley xxmaj xxunk is excellent as the minor city xxunk who suddenly finds himself leading one of the world 's xxunk xxunk . xxmaj xxunk xxmaj margaret xxmaj xxunk is a delight as the history professor who sides with xxmaj xxunk . xxmaj others in the stand - out cast include xxmaj xxunk xxmaj xxunk , xxmaj paul xxmaj xxunk , xxmaj xxunk xxmaj xxunk , xxmaj xxunk xxmaj xxunk & xxmaj sir xxmaj michael xxmaj xxunk . \n",
       " \n",
       "  xxmaj welcome to xxmaj xxunk !"
      ]
     },
     "execution_count": 258,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(movie_reviews.valid.x)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_term_doc_matrix(label_list, vocab_len):\n",
    "    j_indices = []\n",
    "    indptr = []\n",
    "    values = []\n",
    "    indptr.append(0)\n",
    "\n",
    "    for i, doc in enumerate(label_list):\n",
    "        feature_counter = Counter(doc.data)\n",
    "        j_indices.extend(feature_counter.keys())\n",
    "        values.extend(feature_counter.values())\n",
    "        indptr.append(len(j_indices))\n",
    "        \n",
    "#     return (values, j_indices, indptr)\n",
    "\n",
    "    return scipy.sparse.csr_matrix((values, j_indices, indptr),\n",
    "                                   shape=(len(indptr) - 1, vocab_len),\n",
    "                                   dtype=int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 185,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 56 ms, sys: 0 ns, total: 56 ms\n",
      "Wall time: 54.9 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "val_term_doc = get_term_doc_matrix(movie_reviews.valid.x, len(movie_reviews.vocab.itos))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 186,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 212 ms, sys: 4 ms, total: 216 ms\n",
      "Wall time: 210 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "trn_term_doc = get_term_doc_matrix(movie_reviews.train.x, len(movie_reviews.vocab.itos))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(800, 6010)"
      ]
     },
     "execution_count": 187,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trn_term_doc.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 269,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x10 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 10 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 269,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trn_term_doc[:,-10:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(200, 6010)"
      ]
     },
     "execution_count": 188,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_term_doc.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### More data exploration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We could convert our sparse matrix to a dense matrix:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 272,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['sollett']"
      ]
     },
     "execution_count": 272,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[-1:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 189,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[32,  0,  1,  0, ...,  1,  0,  0, 10],\n",
       "        [ 9,  0,  1,  0, ...,  1,  0,  0,  7],\n",
       "        [ 6,  0,  1,  0, ...,  0,  0,  0, 12],\n",
       "        [78,  0,  1,  0, ...,  0,  0,  0, 44],\n",
       "        ...,\n",
       "        [ 8,  0,  1,  0, ...,  0,  0,  0,  8],\n",
       "        [43,  0,  1,  0, ...,  8,  1,  0, 25],\n",
       "        [ 7,  0,  1,  0, ...,  1,  0,  0,  9],\n",
       "        [19,  0,  1,  0, ...,  2,  0,  0,  5]])"
      ]
     },
     "execution_count": 189,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_term_doc.todense()[:10,:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 190,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'xxeos'"
      ]
     },
     "execution_count": 190,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 191,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text xxbos i saw this movie once as a kid on the late - late show and fell in love with it . \n",
       " \n",
       "  xxmaj it took 30 + years , but i recently did find it on xxup dvd - it was n't cheap , either - in a xxunk that xxunk in war movies . xxmaj we watched it last night for the first time . xxmaj the audio was good , however it was grainy and had the trailers between xxunk . xxmaj even so , it was better than i remembered it . i was also impressed at how true it was to the play . \n",
       " \n",
       "  xxmaj the xxunk is around here xxunk . xxmaj if you 're xxunk in finding it , fire me a xxunk and i 'll see if i can get you the xxunk . xxunk"
      ]
     },
     "execution_count": 191,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "review = movie_reviews.valid.x[1]; review"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** Since the word \"late\" shows up twice in this review (\"...as a kid on the late - late show...\"), confirm that a value of 2 is stored in the term-document matrix, for the row corresponding to this review and the column corresponding to the word \"late\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Answer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 194,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "451\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 194,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Exercise: Confirm this\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 195,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<200x6010 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 27848 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 195,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_term_doc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 196,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<1x6010 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 81 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 196,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_term_doc[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 197,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "144"
      ]
     },
     "execution_count": 197,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_term_doc[1].sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The review has 81 distinct tokens in it, and 144 tokens total."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 198,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  2,  19, 248,  21, ...,   9,   0,  10,   0])"
      ]
     },
     "execution_count": 198,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "review.data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise:** How could you convert review.data back to text (without just using review.text)?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Answer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 199,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['xxbos',\n",
       " 'i',\n",
       " 'saw',\n",
       " 'this',\n",
       " 'movie',\n",
       " 'once',\n",
       " 'as',\n",
       " 'a',\n",
       " 'kid',\n",
       " 'on',\n",
       " 'the',\n",
       " 'late',\n",
       " '-',\n",
       " 'late',\n",
       " 'show',\n",
       " 'and',\n",
       " 'fell',\n",
       " 'in',\n",
       " 'love',\n",
       " 'with',\n",
       " 'it',\n",
       " '.',\n",
       " '\\n \\n ',\n",
       " 'xxmaj',\n",
       " 'it',\n",
       " 'took',\n",
       " '30',\n",
       " '+',\n",
       " 'years',\n",
       " ',',\n",
       " 'but',\n",
       " 'i',\n",
       " 'recently',\n",
       " 'did',\n",
       " 'find',\n",
       " 'it',\n",
       " 'on',\n",
       " 'xxup',\n",
       " 'dvd',\n",
       " '-',\n",
       " 'it',\n",
       " 'was',\n",
       " \"n't\",\n",
       " 'cheap',\n",
       " ',',\n",
       " 'either',\n",
       " '-',\n",
       " 'in',\n",
       " 'a',\n",
       " 'xxunk',\n",
       " 'that',\n",
       " 'xxunk',\n",
       " 'in',\n",
       " 'war',\n",
       " 'movies',\n",
       " '.',\n",
       " 'xxmaj',\n",
       " 'we',\n",
       " 'watched',\n",
       " 'it',\n",
       " 'last',\n",
       " 'night',\n",
       " 'for',\n",
       " 'the',\n",
       " 'first',\n",
       " 'time',\n",
       " '.',\n",
       " 'xxmaj',\n",
       " 'the',\n",
       " 'audio',\n",
       " 'was',\n",
       " 'good',\n",
       " ',',\n",
       " 'however',\n",
       " 'it',\n",
       " 'was',\n",
       " 'grainy',\n",
       " 'and',\n",
       " 'had',\n",
       " 'the',\n",
       " 'trailers',\n",
       " 'between',\n",
       " 'xxunk',\n",
       " '.',\n",
       " 'xxmaj',\n",
       " 'even',\n",
       " 'so',\n",
       " ',',\n",
       " 'it',\n",
       " 'was',\n",
       " 'better',\n",
       " 'than',\n",
       " 'i',\n",
       " 'remembered',\n",
       " 'it',\n",
       " '.',\n",
       " 'i',\n",
       " 'was',\n",
       " 'also',\n",
       " 'impressed',\n",
       " 'at',\n",
       " 'how',\n",
       " 'true',\n",
       " 'it',\n",
       " 'was',\n",
       " 'to',\n",
       " 'the',\n",
       " 'play',\n",
       " '.',\n",
       " '\\n \\n ',\n",
       " 'xxmaj',\n",
       " 'the',\n",
       " 'xxunk',\n",
       " 'is',\n",
       " 'around',\n",
       " 'here',\n",
       " 'xxunk',\n",
       " '.',\n",
       " 'xxmaj',\n",
       " 'if',\n",
       " 'you',\n",
       " \"'re\",\n",
       " 'xxunk',\n",
       " 'in',\n",
       " 'finding',\n",
       " 'it',\n",
       " ',',\n",
       " 'fire',\n",
       " 'me',\n",
       " 'a',\n",
       " 'xxunk',\n",
       " 'and',\n",
       " 'i',\n",
       " \"'ll\",\n",
       " 'see',\n",
       " 'if',\n",
       " 'i',\n",
       " 'can',\n",
       " 'get',\n",
       " 'you',\n",
       " 'the',\n",
       " 'xxunk',\n",
       " '.',\n",
       " 'xxunk']"
      ]
     },
     "execution_count": 199,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Exercise\n",
    "\n",
    "[movie_reviews.vocab.itos[a] for a in review.data]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise**: Confirm that review has 81 distinct tokens"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Answer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "81"
      ]
     },
     "execution_count": 200,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Exercise\n",
    "\n",
    "len(set(review.data))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 201,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['state',\n",
       " 'street',\n",
       " 'impossible',\n",
       " 'clever',\n",
       " 'development',\n",
       " 'concept',\n",
       " 'william',\n",
       " 'worked',\n",
       " 'adventure',\n",
       " 'church',\n",
       " 'unlike',\n",
       " 'hold',\n",
       " 'lots',\n",
       " 'premise',\n",
       " 'shooting',\n",
       " 'washington',\n",
       " 'sick',\n",
       " 'effect',\n",
       " 'waiting',\n",
       " 'singing']"
      ]
     },
     "execution_count": 201,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.vocab.itos[1000:1020]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`stoi` (string-to-int) is larger than `itos` (int-to-string)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 202,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "13150"
      ]
     },
     "execution_count": 202,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(movie_reviews.vocab.stoi) - len(movie_reviews.vocab.itos)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is because many words are mapping to unknown.  We can confirm here:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 203,
   "metadata": {},
   "outputs": [],
   "source": [
    "unk = []\n",
    "for word, num in movie_reviews.vocab.stoi.items():\n",
    "    if num==0:\n",
    "        unk.append(word)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 204,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "13151"
      ]
     },
     "execution_count": 204,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(unk)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['xxunk',\n",
       " 'bleeping',\n",
       " 'pert',\n",
       " 'ticky',\n",
       " 'schtick',\n",
       " 'whoosh',\n",
       " 'banzai',\n",
       " 'chill',\n",
       " 'wooofff',\n",
       " 'cheery',\n",
       " 'superstars',\n",
       " 'fashionable',\n",
       " 'cruelly',\n",
       " 'separating',\n",
       " 'mistreat',\n",
       " 'tensions',\n",
       " 'religions',\n",
       " 'baseness',\n",
       " 'nobility',\n",
       " 'puro',\n",
       " 'disowned',\n",
       " 'option',\n",
       " 'faults',\n",
       " 'dignified',\n",
       " 'realisation',\n",
       " 'reconciliation',\n",
       " 'mrs',\n",
       " 'iyer',\n",
       " 'heartbreaking',\n",
       " 'histories',\n",
       " 'frankness',\n",
       " 'starters',\n",
       " 'montage',\n",
       " 'swearing',\n",
       " 'halestorm',\n",
       " 'korea',\n",
       " 'concentrate',\n",
       " 'pic',\n",
       " 'elude',\n",
       " 'characteristics',\n",
       " 'blathered',\n",
       " 'brassed',\n",
       " 'declaration',\n",
       " 'peck',\n",
       " 'garnered',\n",
       " 'fearless',\n",
       " 'tempered',\n",
       " 'humane',\n",
       " 'tails',\n",
       " 'slighted',\n",
       " 'slater',\n",
       " 'barrage',\n",
       " 'underway',\n",
       " 'operating',\n",
       " 'tag',\n",
       " 'dorff',\n",
       " 'reid',\n",
       " 'continually',\n",
       " 'revel',\n",
       " 'nra',\n",
       " 'benton',\n",
       " 'slate',\n",
       " 'penal',\n",
       " 'vengeful',\n",
       " 'seed',\n",
       " 'backbone',\n",
       " 'dismal',\n",
       " 'fortunate',\n",
       " 'ds',\n",
       " 'tmob',\n",
       " 'autographed',\n",
       " 'intercepted',\n",
       " 'lectured',\n",
       " 'reprints',\n",
       " 'comicon',\n",
       " 'attendees',\n",
       " 'blackhawk',\n",
       " 'insisted',\n",
       " 'jumped',\n",
       " 'apologized',\n",
       " 'wishing',\n",
       " 'seller',\n",
       " 'abomination',\n",
       " 'crib',\n",
       " 'seriousness',\n",
       " 'reclaim',\n",
       " 'sidenotes',\n",
       " 'archenemy',\n",
       " 'simultaneous',\n",
       " 'sheet',\n",
       " 'ely',\n",
       " 'leaping',\n",
       " 'brick',\n",
       " 'blasting',\n",
       " 'pistol',\n",
       " 'duster',\n",
       " 'postscript',\n",
       " 'accompanied',\n",
       " '1975',\n",
       " 'smack']"
      ]
     },
     "execution_count": 205,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "unk[:100]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Naive Bayes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We define the **log-count ratio** $r$ for each word $f$:\n",
    "\n",
    "$r = \\log \\frac{\\text{ratio of feature $f$ in positive documents}}{\\text{ratio of feature $f$ in negative documents}}$\n",
    "\n",
    "where ratio of feature $f$ in positive documents is the number of times a positive document has a feature divided by the number of positive documents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 281,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['negative', 'positive']"
      ]
     },
     "execution_count": 281,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.y.classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 282,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = trn_term_doc\n",
    "y = movie_reviews.train.y\n",
    "val_y = movie_reviews.valid.y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 283,
   "metadata": {},
   "outputs": [],
   "source": [
    "positive = y.c2i['positive']\n",
    "negative = y.c2i['negative']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 284,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(6010, 6010)"
      ]
     },
     "execution_count": 284,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(p1), len(p0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 285,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'xxunk'"
      ]
     },
     "execution_count": 285,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.itos[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 286,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7153,    0,  417,    0, ...,    0,    3,    3,    3], dtype=int64)"
      ]
     },
     "execution_count": 286,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.squeeze(np.asarray(x[y.items==negative].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 287,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[6468,    0,  383,    0, ...,    3,    0,    0,    0]], dtype=int64)"
      ]
     },
     "execution_count": 287,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.asarray(x[y.items==positive].sum(0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 288,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([6468,    0,  383,    0, ...,    3,    0,    0,    0], dtype=int64)"
      ]
     },
     "execution_count": 288,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.squeeze(np.asarray(x[y.items==positive].sum(0)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For each word in our vocabulary, we are summing up how many positive reviews it is in, and how many negative reviews."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 289,
   "metadata": {},
   "outputs": [],
   "source": [
    "p1 = np.squeeze(np.asarray(x[y.items==positive].sum(0)))\n",
    "p0 = np.squeeze(np.asarray(x[y.items==negative].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 290,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 6468,     0,   383,     0,     0, 10267,   674,    57,     0,  5260], dtype=int64)"
      ]
     },
     "execution_count": 290,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p1[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 291,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = movie_reviews.vocab"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using our ratios for even more data exploration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use p0 and p1 to do some more data exploration!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise**: compare how often \"loved\" appears in positive reviews vs. negative reviews.  How about \"hate\"?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Answer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 217,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(12, 29)"
      ]
     },
     "execution_count": 217,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Exercise: How often does the word \"loved\" appear in neg vs. pos reviews?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 218,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(6, 3)"
      ]
     },
     "execution_count": 218,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Exercise: How often does the word \"hated\" appear in neg vs. pos reviews?\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### positive reviews with the word \"hated\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I was curious to look at an example of a postive review with the word \"hated\" in it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 219,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1977"
      ]
     },
     "execution_count": 219,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.stoi['hated']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 220,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 15,  49, 304, 351, 393, 612, 695, 773], dtype=int32)"
      ]
     },
     "execution_count": 220,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.argwhere((x[:,1977] > 0))[:,0]; a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 221,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  1,   3,  10,  11, ..., 787, 789, 790, 797])"
      ]
     },
     "execution_count": 221,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.argwhere(y.items==positive)[:,0]; b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 222,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{393, 612, 695}"
      ]
     },
     "execution_count": 222,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set(a).intersection(set(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 223,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"xxbos xxmaj xxunk , yeah this episode is extremely underrated . \\n \\n  xxmaj even though there is a xxup lot of bad writing and acting at parts . i think the good over wins the bad . \\n \\n  i love the xxunk parts and the big ' twist ' at the end . i absolutely love that scene when xxmaj michelle xxunk xxmaj tony . xxmaj it 's actually one of my favorite scenes of xxmaj season 1 . \\n \\n  xxmaj for some reason , people have always hated the xxmaj xxunk episodes , yet i have always liked them . xxmaj they 're not the best , in terms of writing . but the theme really does interest me , \\n \\n  i 'm gon na give it a xxup three star , but if the writing were a little more consistent i 'd give it xxup four .\""
      ]
     },
     "execution_count": 223,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "review = movie_reviews.train.x[695]\n",
    "review.text"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### negative reviews with the word \"loved\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, let's look at an example of a negative review that contains the word \"loved\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 224,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "535"
      ]
     },
     "execution_count": 224,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.stoi['loved']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 225,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  0,  19,  24,  51,  61,  70,  81, 110, 123, 155, 175, 193, 221, 265, 274, 279, 284, 290, 295, 304, 360, 384,\n",
       "       421, 465, 516, 520, 548, 569, 588, 604, 620, 631, 661, 672, 679, 702, 709, 759, 764, 792], dtype=int32)"
      ]
     },
     "execution_count": 225,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.argwhere((x[:,534] > 0))[:,0]; a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 226,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  0,   2,   4,   5, ..., 795, 796, 798, 799])"
      ]
     },
     "execution_count": 226,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.argwhere(y.items==negative)[:,0]; b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 227,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0,\n",
       " 24,\n",
       " 51,\n",
       " 70,\n",
       " 81,\n",
       " 123,\n",
       " 155,\n",
       " 193,\n",
       " 221,\n",
       " 274,\n",
       " 279,\n",
       " 284,\n",
       " 290,\n",
       " 295,\n",
       " 304,\n",
       " 421,\n",
       " 516,\n",
       " 548,\n",
       " 604,\n",
       " 620,\n",
       " 631,\n",
       " 672,\n",
       " 679,\n",
       " 709,\n",
       " 759,\n",
       " 764,\n",
       " 792}"
      ]
     },
     "execution_count": 227,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set(a).intersection(set(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 323,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'xxbos xxmaj this is not really a zombie film , if we \\'re xxunk zombies as the dead walking around . xxmaj here the protagonist , xxmaj xxunk xxmaj louque ( played by an xxunk young xxmaj dean xxmaj xxunk ) , xxunk control of a method to create zombies , though in fact , his \\' method \\' is to mentally project his thoughts and control other living people \\'s minds turning them into xxunk slaves . xxmaj this is an interesting concept for a movie , and was done much more effectively by xxmaj xxunk xxmaj lang in his series of \\' xxmaj dr. xxmaj mabuse \\' films , including \\' xxmaj dr. xxmaj mabuse the xxmaj xxunk \\' ( xxunk ) and \\' xxmaj the xxmaj testament of xxmaj dr. xxmaj mabuse \\' ( 1933 ) . xxmaj here it is unfortunately xxunk to his quest to regain the love of his former fiancée , xxmaj claire xxmaj duvall ( played by the xxmaj anne xxmaj xxunk look alike with a bad xxunk , xxmaj dorothy xxmaj stone ) which is really the major theme . \\n \\n  xxmaj the movie has an intriguing beginning , as xxmaj louque is sent on a military xxunk expedition to xxmaj xxunk to end the cult of zombies that came from there . xxmaj at some type of compound ( where we get great 30s sets and clothes ) he xxunk his xxunk to xxmaj claire , and then barely five minutes later , she gives him back his ring xxunk her love for his pal , xxmaj xxunk xxmaj greyson ( xxmaj robert xxmaj xxunk ) . xxmaj it \\'s unintentionally funny the way they talk to each other without making eye contact . xxmaj this would have been a great movie for \\' xxmaj mystery xxmaj science xxmaj theater xxunk \\' , if they had n\\'t already xxunk it . \\n \\n  xxmaj it \\'s never shown how xxmaj louque actually learns the \\' xxunk \\' secret , but he then uses it to kill his enemies , create a giant army of xxunk carrying soldiers and body guards . xxmaj we wo n\\'t see such sheer force of will until xxmaj john xxmaj xxunk in \\' xxmaj the xxmaj brain xxmaj from xxmaj planet xxmaj xxunk \\' ( xxunk ) . \\n \\n  xxmaj finally xxmaj claire xxunk to marry him if he will let xxmaj greyson live and return to xxmaj america . xxmaj louque agrees , but actually turns him into one of his xxunk slaves . xxmaj on their wedding night he realizes that xxmaj claire will only begin to love him if he gives up his \\' powers . \\' xxmaj to gain her love , he does so , causing the \\' revolt \\' of the title , in which all his slaves xxunk and attack his compound and kill him . xxmaj greyson xxunk xxmaj claire , and we seem to be at the end of a parable : \" xxmaj whom the xxunk would destroy , they first make mad . \" \\n \\n  xxmaj so really then , it \\'s not that bad of a film , despite the low imdb rating it currently has . xxmaj on repeated viewings ( ? ) one can see the xxunk in the well formed script ! xxmaj dean xxmaj xxunk had yet to develop into a good actor , and is almost unrecognizable in his xxunk -- is that really his own hair ? xxmaj we remember him more for his xxunk , old man roles in \\' xxmaj white xxmaj christmas \\' ( xxunk ) , \\' x xxmaj the xxmaj unknown \\' ( 1956 ) and \\' xxmaj king xxmaj xxunk \\' ( 1958 ) . xxmaj the story xxunk a lot of its basic themes from the xxmaj xxunk brothers better , earlier film \\' xxmaj white xxmaj zombie \\' ( xxunk ) in which xxunk xxmaj robert xxmaj xxunk ( as xxmaj charles xxmaj xxunk ) uses \\' xxunk \\' to win the love of xxmaj xxunk xxmaj xxunk ( as xxmaj xxunk xxmaj parker ) . \\n \\n  xxmaj if you want real zombie movies ( of which there are hundreds ! ) i \\'d start with \\' xxmaj white xxmaj zombie \\' ( xxunk ) , \\' xxmaj king of the xxmaj zombies \\' ( xxunk ) , \\' i xxmaj walked with a xxmaj zombie \\' ( xxunk ) , \\' xxmaj night of the xxmaj living xxmaj dead \\' ( xxunk ) , \\' xxmaj the xxmaj last xxmaj man on xxmaj earth \\' ( 1964 ) and its two xxunk . xxmaj in the modern era of classy films , there are \\' xxmaj horror xxmaj express \\' ( 1972 ) , \\' xxmaj the xxmaj xxunk and the xxmaj xxunk \\' ( xxunk ) , \\' 28 xxmaj days xxmaj later \\' ( 2002 ) and its sequel , as well as many , many , others too numerous to mention . \\n \\n  xxmaj this one is not really a zombie film . xxmaj judging this movie on its own terms , it \\'s more of a semi - xxmaj gothic romance . xxmaj as such it ranks a little below some of xxmaj universal \\'s bottom billed b horror movies of the late 30s and early xxunk . xxmaj so i \\'ll give it a 5 .'"
      ]
     },
     "execution_count": 323,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "review = movie_reviews.train.x[792]\n",
    "review.text"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Applying Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 289,
   "metadata": {},
   "outputs": [],
   "source": [
    "p1 = np.squeeze(np.asarray(x[y.items==positive].sum(0)))\n",
    "p0 = np.squeeze(np.asarray(x[y.items==negative].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 292,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 293,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.015811,  0.084839,  0.      ,  0.084839, ...,  1.471133, -1.301455, -1.301455, -1.301455])"
      ]
     },
     "execution_count": 293,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r = np.log(pr1/pr0); r"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Vocab most likely associated with positive/negative reviews"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 312,
   "metadata": {},
   "outputs": [],
   "source": [
    "biggest = np.argpartition(r, -10)[-10:]\n",
    "smallest = np.argpartition(r, 10)[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most positive words:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 313,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['paxton',\n",
       " 'gilliam',\n",
       " 'davies',\n",
       " 'jabba',\n",
       " 'jimmy',\n",
       " 'felix',\n",
       " 'biko',\n",
       " 'fanfan',\n",
       " 'astaire',\n",
       " 'noir']"
      ]
     },
     "execution_count": 313,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[v.itos[k] for k in biggest]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 319,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "515"
      ]
     },
     "execution_count": 319,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.argmax(trn_term_doc[:,v.stoi['biko']])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 324,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text xxbos \" xxmaj the xxmaj true xxmaj story xxmaj of xxmaj the xxmaj friendship xxmaj that xxmaj shook xxmaj south xxmaj africa xxmaj and xxmaj xxunk xxmaj the xxmaj world . \" \n",
       " \n",
       "  xxmaj richard xxmaj attenborough , who directed \" a xxmaj bridge xxmaj too xxmaj far \" and \" xxmaj gandhi \" , wanted to bring the story of xxmaj steve xxmaj biko to life , and the journey and trouble that xxunk xxmaj donald xxmaj woods went through in order to get his story told . xxmaj the films uses xxmaj wood 's two books for it 's information and basis - \" xxmaj biko \" and \" xxmaj asking for xxmaj trouble \" . \n",
       " \n",
       "  xxmaj the film takes place in the late 1970 's , in xxmaj south xxmaj africa . xxmaj south xxmaj africa is in the grip of the terrible apartheid , which keeps the blacks separated from the whites and xxunk the whites as the superior race . xxmaj the blacks are forced to live in xxunk on the xxunk of the cities and xxunk , and they come under frequent xxunk by the police and the army . xxmaj we are shown a dawn xxunk on a xxunk , as xxunk and armed police force their way through the camp beating and even killing the inhabitants . xxmaj then we are introduced to xxmaj donald xxmaj woods ( xxmaj kevin xxmaj kline ) , who is the editor of a popular newspaper . xxmaj after xxunk a negative story about black xxunk xxmaj steve xxmaj biko ( xxmaj denzel xxmaj washington ) , xxmaj woods goes to meet with him . xxmaj the two are xxunk of each other at first , but they soon become good friends and xxmaj biko shows the horrors of the apartheid system from a black persons point of view to xxmaj woods . xxmaj this xxunk xxmaj woods to speak out against what 's happening around him , and makes him desperate to bring xxmaj steve xxmaj biko 's story out of the xxunk of the white man 's xxmaj south xxmaj africa and to the world . xxmaj soon , xxmaj steve xxmaj biko is arrested and is killed in prison . xxmaj now xxmaj woods and his family are daring to escape from xxmaj south xxmaj africa to xxmaj england , where xxmaj woods can xxunk his book about xxmaj steve xxmaj biko and the apartheid . \n",
       " \n",
       "  xxmaj when i first heard of \" xxmaj cry xxmaj freedom \" , i was under the impression that it was a movie completely dedicated to the life of xxmaj steve xxmaj biko . i had never actually heard of xxmaj steve xxmaj biko before i seen this film , as the events in this film were really before my time . xxmaj but it 's more about the story of xxmaj donald xxmaj woods and his journey across the border into xxmaj xxunk as he tried to xxunk the xxmaj south xxmaj african xxunk . xxmaj woods was put on a five year type house xxunk after xxmaj steve xxmaj biko was killed . xxmaj so in order to xxunk his xxunk on xxmaj steve xxmaj biko , he had to escape . xxmaj because the xxunk would be considered xxunk in xxmaj south xxmaj africa and that could have resulted in xxmaj woods meeting a fate similar to that of xxmaj biko 's . xxmaj the real xxmaj donald xxmaj woods and his wife acted as xxunk to this film . \n",
       " \n",
       "  xxmaj denzel xxmaj washington is only in the film for the first hour , and i was disappointed with that as i was expecting to see him for the entire movie . xxmaj but he was amazing as xxmaj steve xxmaj biko , and captured his personality from what i 've read really well and his accent sounded perfect . xxmaj his performance earned him an xxmaj oscar nomination for xxmaj best xxmaj supporting xxmaj actor . xxmaj kevin xxmaj kline delivers a excellent and thought - xxunk performance as xxmaj donald xxmaj woods , and xxmaj penelope xxmaj xxunk is excellent as his wife xxmaj xxunk . \n",
       " \n",
       "  xxmaj filming took place in xxmaj xxunk , as needless to say problems xxunk when they tried to film it in xxmaj south xxmaj africa . xxmaj while in xxmaj south xxmaj africa , the xxmaj south xxmaj african xxunk followed the film crew everywhere , so they got the bad xxunk and they pulled out and went to xxunk xxmaj xxunk instead . xxmaj despite everything , and the fact that the apartheid did n't end ' xxunk seven years later , \" xxmaj cry xxmaj freedom \" was n't xxunk in xxmaj south xxmaj africa . xxmaj but xxunk showing the movie received bomb threats . \n",
       " \n",
       "  xxmaj richard xxmaj attenborough brings the horrors of the apartheid to the screen with extreme force and determination . xxmaj he does n't hold back at the end of the movie when showing what was supposed to be a xxunk xxunk by students in a xxunk , turns into a massacre when police open fire on them . xxmaj the film ends with the names of all the anti - apartheid xxunk who died in prison , and the explanations for their deaths . xxmaj many had \" xxmaj no xxmaj explanation \" . xxmaj quite a few were \" xxmaj xxunk \" , which is hard to believe , and many more either fell from the top of the xxunk or were \" xxmaj suicide from xxmaj hanging \" . xxmaj no one will ever know what really happened to them , but i think it 's fair to say that none of these men died at their own hands , but at the hands of others ; or to be more xxunk , at the hands of the police . \n",
       " \n",
       "  \" xxmaj cry xxmaj freedom \" is a must - see movie for it 's portrayal and story of xxmaj steve xxmaj biko . xxmaj it 's also a xxunk and xxunk portrayal of a beautiful land divided and in the xxunk grips of racial xxunk and violence ."
      ]
     },
     "execution_count": 324,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.train.x[515]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most negative words:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 316,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['dog',\n",
       " 'disappointment',\n",
       " 'naschy',\n",
       " 'vargas',\n",
       " 'worst',\n",
       " 'crap',\n",
       " 'crater',\n",
       " 'porn',\n",
       " 'soderbergh',\n",
       " 'fuqua']"
      ]
     },
     "execution_count": 316,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[v.itos[k] for k in smallest]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 317,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "434"
      ]
     },
     "execution_count": 317,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.argmax(trn_term_doc[:,v.stoi['soderbergh']])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 325,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text xxbos xxmaj now that xxmaj che(2008 ) has finished its relatively short xxmaj australian cinema run ( extremely limited xxunk screen in xxmaj xxunk , after xxunk ) , i can xxunk join both xxunk of \" xxmaj at xxmaj the xxmaj movies \" in taking xxmaj steven xxmaj soderbergh to task . \n",
       " \n",
       "  xxmaj it 's usually satisfying to watch a film director change his style / subject , but xxmaj soderbergh 's most recent stinker , xxmaj the xxmaj girlfriend xxmaj xxunk ) , was also missing a story , so narrative ( and editing ? ) seem to suddenly be xxmaj soderbergh 's main challenge . xxmaj strange , after xxunk years in the business . xxmaj he was probably never much good at narrative , just xxunk it well inside \" edgy \" projects . \n",
       " \n",
       "  xxmaj none of this excuses him this present , almost diabolical failure . xxmaj as xxmaj david xxmaj xxunk xxunk , \" two parts of xxmaj che do n't ( even ) make a whole \" . \n",
       " \n",
       "  xxmaj epic xxunk in name only , xxmaj che(2008 ) barely qualifies as a feature film ! xxmaj it certainly has no legs , xxunk as except for its xxunk ultimate resolution forced upon it by history , xxmaj soderbergh 's xxunk - long xxunk just goes nowhere . \n",
       " \n",
       "  xxmaj even xxmaj margaret xxmaj xxunk , the more xxunk of xxmaj australia 's xxmaj at xxmaj the xxmaj movies duo , noted about xxmaj soderbergh 's xxunk waste of ( xxup xxunk digital xxunk ) : \" you 're in the woods ... xxunk in the woods ... xxunk in the woods ... \" . i too am surprised xxmaj soderbergh did n't give us another xxunk of xxup that somewhere between his xxunk two xxmaj parts , because he still left out massive xxunk of xxmaj che 's \" xxunk \" life ! \n",
       " \n",
       "  xxmaj for a xxunk of an important but infamous historical figure , xxmaj soderbergh xxunk xxunk , if not deliberately insults , his audiences by \n",
       " \n",
       "  1 . never providing most of xxmaj che 's story ; \n",
       " \n",
       "  2 . xxunk xxunk film xxunk with mere xxunk xxunk ; \n",
       " \n",
       "  3 . xxunk both true xxunk and a narrative of events ; \n",
       " \n",
       "  4 . barely developing an idea , or a character ; \n",
       " \n",
       "  5 . remaining xxunk episodic ; \n",
       " \n",
       "  6 . xxunk proper context for scenes --- whatever we do get is xxunk in xxunk xxunk ; \n",
       " \n",
       "  7 . xxunk xxunk all audiences ( even xxmaj spanish - xxunk will be confused by the xxunk xxunk in xxmaj english ) ; and \n",
       " \n",
       "  8 . xxunk xxunk his main subject into one dimension . xxmaj why , at xxup this late stage ? xxmaj the t - shirt franchise has been a success ! \n",
       " \n",
       "  xxmaj our sense of xxunk is surely due to xxmaj peter xxmaj xxunk and xxmaj benjamin xxunk xxmaj xxunk xxunk their screenplay solely on xxmaj xxunk 's memoirs . xxmaj so , like a poor student who has read only xxup one of his xxunk xxunk for his xxunk , xxmaj soderbergh 's product is xxunk limited in perspective . \n",
       " \n",
       "  xxmaj the audience is held captive within the same xxunk knowledge , scenery and circumstances of the \" revolutionaries \" , but that does n't xxunk our sympathy . xxmaj instead , it xxunk on us that \" xxmaj ah , xxmaj soderbergh 's trying to xxunk his audiences the same as the xxmaj latino peasants were at the time \" . xxmaj but these are the xxup same illiterate xxmaj latino peasants who xxunk out the good doctor to his enemies . xxmaj why does xxmaj soderbergh feel the need to xxunk us with them , and keep us equally mentally captive ? xxmaj such audience xxunk must have a purpose . \n",
       " \n",
       "  xxmaj part2 is more xxunk than xxmaj part1 , but it 's literally mind - numbing with its repetitive bush - bashing , misery of xxunk , and lack of variety or character xxunk . deltoro 's xxmaj che has no opportunity to grow as a person while he struggles to xxunk his own ill - xxunk troops . xxmaj the only xxunk is the humour as xxmaj che deals with his sometimes deeply ignorant \" revolutionaries \" , some of whom xxunk lack self - control around local peasants or food . xxmaj we certainly get no insight into what caused the conditions , nor any xxunk xxunk of their xxunk xxunk , such as it was . \n",
       " \n",
       "  xxmaj part2 's xxunk xxunk remains xxunk episodic : again , nothing is telegraphed or xxunk . xxmaj thus even the scenes with xxmaj xxunk xxmaj xxunk ( xxmaj xxunk xxmaj xxunk ) are unexpected and disconcerting . xxmaj any xxunk events are portrayed xxunk and xxmaj latino - xxunk , with xxmaj part1 's interviews xxunk by time - xxunk xxunk between the corrupt xxmaj xxunk president ( xxmaj xxunk de xxmaj xxunk ) and xxup us xxmaj government xxunk promising xxup cia xxunk ( ! ) . \n",
       " \n",
       "  xxmaj the rest of xxmaj part2 's \" woods \" and day - for - night blue xxunk just xxunk the audience until they 're xxunk the xxunk . \n",
       " \n",
       "  xxmaj perhaps deltoro felt too xxunk the frustration of many non - xxmaj american xxmaj latinos about never getting a truthful , xxunk history of xxmaj che 's xxunk within their own countries . xxmaj when foreign xxunk still wo n't deliver a free press to their people -- for whatever reason -- then one can see how a popular xxmaj american indie producer might set out to xxunk the not - so - well - read ( \" i may not be able to read or write , but i 'm xxup not xxunk . xxmaj the xxmaj inspector xxmaj xxunk ) ) out to their own local xxunk . xxmaj the film 's obvious xxunk and gross over - xxunk hint very strongly that it 's aiming only at the xxunk of the less - informed xxup who xxup still xxup speak xxup little xxmaj english . xxmaj if they did , they 'd have read xxunk on the subject already , and xxunk the relevant social issues amongst themselves -- learning the lessons of history as they should . \n",
       " \n",
       "  xxmaj such insights are precisely what societies still need -- and not just the remaining illiterate xxmaj latinos of xxmaj central and xxmaj south xxmaj america -- yet it 's what xxmaj che(2008 ) xxunk fails to deliver . xxmaj soderbergh xxunk his lead because he 's weak on narrative . i am xxunk why xxmaj xxunk deltoro deliberately chose xxmaj soderbergh for this project if he knew this . xxmaj it 's been xxunk , xxunk about xxmaj xxunk was xxunk wanted : it 's what i went to see this film for , but the director xxunk robs us of that . \n",
       " \n",
       "  xxmaj david xxmaj xxunk , writing in xxmaj the xxmaj australian ( xxunk ) observed that while xxmaj part1 was \" uneven \" , xxmaj part2 actually \" goes rapidly downhill \" from there , \" xxunk xxmaj che 's final xxunk in xxmaj xxunk in xxunk detail \" , which \" ... feels almost unbearably slow and turgid \" . \n",
       " \n",
       "  xxmaj che : xxmaj the xxmaj xxunk aka xxmaj part2 is certainly no xxunk for xxmaj xxunk , painting it a picture of misery and xxunk . xxmaj the entire second half is only xxunk by the aforementioned humour , and the dramatic -- yet tragic -- capture and execution of the film 's subject . \n",
       " \n",
       "  xxmaj the rest of this xxunk cinema xxunk is just confusing , irritating misery -- xxunk , for a xxmaj soderbergh film , to be avoided at all costs . xxmaj it is bound to break the hearts of all who know even just a xxunk about the xxunk / 10 )"
      ]
     },
     "execution_count": 325,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_reviews.train.x[434]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 322,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x1 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 1 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 322,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trn_term_doc[:,v.stoi['soderbergh']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 316,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['dog',\n",
       " 'disappointment',\n",
       " 'naschy',\n",
       " 'vargas',\n",
       " 'worst',\n",
       " 'crap',\n",
       " 'crater',\n",
       " 'porn',\n",
       " 'soderbergh',\n",
       " 'fuqua']"
      ]
     },
     "execution_count": 316,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[v.itos[k] for k in smallest]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Continuing with Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.47875, 0.52125)"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(y.items==positive).mean(), (y.items==negative).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [],
   "source": [
    "preds = (val_term_doc @ r + b) > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.645"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(preds == val_y.items).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Switching to full data set"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have our approach working on a smaller sample of the data, we can try using it on the full dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Download data and process"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 326,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[PosixPath('/home/racheltho/.fastai/data/imdb/unsup'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/imdb.vocab'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/models'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/tmp_lm'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/train'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/test'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/README'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/tmp_clas'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/imdb_textlist_class'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/lm_databunch')]"
      ]
     },
     "execution_count": 326,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "path = untar_data(URLs.IMDB)\n",
    "path.ls()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 327,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[PosixPath('/home/racheltho/.fastai/data/imdb/train/pos'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/train/unsupBow.feat'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/train/labeledBow.feat'),\n",
       " PosixPath('/home/racheltho/.fastai/data/imdb/train/neg')]"
      ]
     },
     "execution_count": 327,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(path/'train').ls()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 328,
   "metadata": {},
   "outputs": [],
   "source": [
    "reviews_full = (TextList.from_folder(path)\n",
    "             #grab all the text files in path\n",
    "             .split_by_folder(valid='test')\n",
    "             #split by train and valid folder (that only keeps 'train' and 'test' so no need to filter)\n",
    "             .label_from_folder(classes=['neg', 'pos']))\n",
    "             #label them all with their folders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 329,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(25000, 25000)"
      ]
     },
     "execution_count": 329,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(reviews_full.train), len(reviews_full.valid)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will store the vocab in a variable `v` since we will be using it frequently:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 330,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = reviews_full.vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 331,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['bad',\n",
       " 'people',\n",
       " 'will',\n",
       " 'other',\n",
       " 'also',\n",
       " 'into',\n",
       " 'first',\n",
       " 'because',\n",
       " 'great',\n",
       " 'how']"
      ]
     },
     "execution_count": 331,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.itos[100:110]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 332,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4.57 s, sys: 116 ms, total: 4.69 s\n",
      "Wall time: 4.56 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "val_term_doc = get_term_doc_matrix(reviews_full.valid.x, len(reviews_full.vocab.itos))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 333,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 5.1 s, sys: 236 ms, total: 5.34 s\n",
      "Wall time: 5.01 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "trn_term_doc = get_term_doc_matrix(reviews_full.train.x, len(reviews_full.vocab.itos))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That was slow.  Let's save our matrices for faster loading next time:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 334,
   "metadata": {},
   "outputs": [],
   "source": [
    "scipy.sparse.save_npz(\"trn_term_doc.npz\", trn_term_doc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 335,
   "metadata": {},
   "outputs": [],
   "source": [
    "scipy.sparse.save_npz(\"val_term_doc.npz\", val_term_doc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When storing data like this, always make sure it's included in your .gitignore file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the future, we'll just be able to load our data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "trn_term_doc = scipy.sparse.load_npz(\"trn_term_doc.npz\")\n",
    "val_term_doc = scipy.sparse.load_npz(\"val_term_doc.npz\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Naive Bayes on full dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 336,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=trn_term_doc\n",
    "y=reviews_full.train.y\n",
    "\n",
    "val_y = reviews_full.valid.y.items"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 337,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<25000x38457 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 3716501 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 337,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 338,
   "metadata": {},
   "outputs": [],
   "source": [
    "positive = y.c2i['pos']\n",
    "negative = y.c2i['neg']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 339,
   "metadata": {},
   "outputs": [],
   "source": [
    "p0 = np.squeeze(np.asarray(x[y.items==negative].sum(0)))\n",
    "p1 = np.squeeze(np.asarray(x[y.items==positive].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 340,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 28399,      0,  12500,      0,      0, 342576,  20471,   1338,      7, 173118, 137954, 143763,  89571,  83406,\n",
       "        76828,  66715,  58511,  47892,  50178,  40448], dtype=int64)"
      ]
     },
     "execution_count": 340,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p1[:20]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Data exploration: negative to positive ratios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I was curious about the ratio of times a given word appears in negative reviews to times it occurs in positive reviews.  Bigger ratios (> 1) mean the word is indicative of a negative review, and smaller ratios (< 1) mean it is indicative of a positive review."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 341,
   "metadata": {},
   "outputs": [],
   "source": [
    "def neg_pos_given_word(word):\n",
    "    print(p0[v.stoi[word]]/p1[v.stoi[word]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 342,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.051546391752577\n"
     ]
    }
   ],
   "source": [
    "neg_pos_given_word('hated')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 343,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.6424702058504875\n"
     ]
    }
   ],
   "source": [
    "neg_pos_given_word('liked')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 344,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.3139963167587477\n"
     ]
    }
   ],
   "source": [
    "neg_pos_given_word('loved')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 345,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.48538961038961037\n"
     ]
    }
   ],
   "source": [
    "neg_pos_given_word('best')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 346,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.837301587301587\n"
     ]
    }
   ],
   "source": [
    "neg_pos_given_word('worst')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 347,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 348,
   "metadata": {},
   "outputs": [],
   "source": [
    "r = np.log(pr1/pr0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 349,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.7133498878774648"
      ]
     },
     "execution_count": 349,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r[v.stoi['hated']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 350,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.1563661500586044"
      ]
     },
     "execution_count": 350,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r[v.stoi['loved']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 351,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-2.2826243504315076"
      ]
     },
     "execution_count": 351,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r[v.stoi['worst']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 352,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7225576052173609"
      ]
     },
     "execution_count": 352,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r[v.stoi['best']]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Back to Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 353,
   "metadata": {},
   "outputs": [],
   "source": [
    "negative = y.c2i['neg']\n",
    "p0 = np.squeeze(np.asarray(x[y.items==negative].sum(0)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we have equal numbers of positive and negative reviews in this data set, b is 0."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 354,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 355,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.0"
      ]
     },
     "execution_count": 355,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean()); b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 357,
   "metadata": {},
   "outputs": [],
   "source": [
    "preds = (val_term_doc @ r + b) > 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our accuracy is 80% for the full data set:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 358,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.80864"
      ]
     },
     "execution_count": 358,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(preds == val_y).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Binarized Naive Bayes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Maybe it only matters whether a word is in the review or not (not the frequency of the word):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 359,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=trn_term_doc.sign()\n",
    "y=reviews_full.train.y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 366,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1, 0, 1, 0, ..., 0, 0, 0, 1],\n",
       "        [0, 0, 1, 0, ..., 0, 0, 0, 1],\n",
       "        [1, 0, 1, 0, ..., 1, 0, 0, 1],\n",
       "        [1, 0, 1, 0, ..., 0, 0, 0, 1],\n",
       "        ...,\n",
       "        [0, 0, 1, 0, ..., 0, 0, 0, 1],\n",
       "        [1, 0, 1, 0, ..., 1, 0, 0, 1],\n",
       "        [1, 0, 1, 0, ..., 1, 0, 0, 1],\n",
       "        [0, 0, 1, 0, ..., 0, 0, 0, 1]])"
      ]
     },
     "execution_count": 366,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.todense()[:10,:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 360,
   "metadata": {},
   "outputs": [],
   "source": [
    "negative = y.c2i['neg']\n",
    "positive = y.c2i['pos']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 361,
   "metadata": {},
   "outputs": [],
   "source": [
    "p1 = np.squeeze(np.asarray(x[y.items==positive].sum(0)))\n",
    "p0 = np.squeeze(np.asarray(x[y.items==negative].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 362,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 364,
   "metadata": {},
   "outputs": [],
   "source": [
    "r = np.log(pr1/pr0)\n",
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean())\n",
    "\n",
    "preds = (val_term_doc.sign() @ r + b) > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 365,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.82908"
      ]
     },
     "execution_count": 365,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(preds==val_y).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Logistic regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is how we can fit logistic regression where the features are the unigrams."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LogisticRegression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8828"
      ]
     },
     "execution_count": 148,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = LogisticRegression(C=0.1, dual=True)\n",
    "m.fit(x, y.items.astype(int))\n",
    "preds = m.predict(val_term_doc)\n",
    "(preds==val_y).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And the binarized version:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.88528"
      ]
     },
     "execution_count": 149,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = LogisticRegression(C=0.1, dual=True)\n",
    "m.fit(trn_term_doc.sign(), y.items.astype(int))\n",
    "preds = m.predict(val_term_doc.sign())\n",
    "(preds==val_y).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Trigram with NB features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our next model is a version of logistic regression with Naive Bayes features described [here](https://www.aclweb.org/anthology/P12-2018). For every document we compute binarized features as described above, but this time we use bigrams and trigrams too. Each feature is a log-count ratio. A logistic regression model is then trained to predict sentiment."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ngrams"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An n-gram is a contiguous sequence of n items (where the items can be characters, syllables, or words).  A 1-gram is a unigram, a 2-gram is a bigram, and a 3-gram is a trigram.\n",
    "\n",
    "Here, we are referring to sequences of words. So examples of bigrams include \"the dog\", \"said that\", and \"can't you\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 367,
   "metadata": {},
   "outputs": [],
   "source": [
    "path = untar_data(URLs.IMDB_SAMPLE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 368,
   "metadata": {},
   "outputs": [],
   "source": [
    "movie_reviews = (TextList.from_csv(path, 'texts.csv', cols='text')\n",
    "                .split_from_df(col=2)\n",
    "                .label_from_df(cols=0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 369,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = movie_reviews.vocab.itos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 370,
   "metadata": {},
   "outputs": [],
   "source": [
    "vocab_len = len(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Our data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create train matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 371,
   "metadata": {},
   "outputs": [],
   "source": [
    "min_n=1\n",
    "max_n=3\n",
    "\n",
    "j_indices = []\n",
    "indptr = []\n",
    "values = []\n",
    "indptr.append(0)\n",
    "num_tokens = vocab_len\n",
    "\n",
    "itongram = dict()\n",
    "ngramtoi = dict()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will iterate through the sequences of words to create our n-grams:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 372,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i, doc in enumerate(movie_reviews.train.x):\n",
    "    feature_counter = Counter(doc.data)\n",
    "    j_indices.extend(feature_counter.keys())\n",
    "    values.extend(feature_counter.values())\n",
    "    this_doc_ngrams = list()\n",
    "\n",
    "    m = 0\n",
    "    for n in range(min_n, max_n + 1):\n",
    "        for k in range(vocab_len - n + 1):\n",
    "            ngram = doc.data[k: k + n]\n",
    "            if str(ngram) not in ngramtoi:\n",
    "                if len(ngram)==1:\n",
    "                    num = ngram[0]\n",
    "                    ngramtoi[str(ngram)] = num\n",
    "                    itongram[num] = ngram\n",
    "                else:\n",
    "                    ngramtoi[str(ngram)] = num_tokens\n",
    "                    itongram[num_tokens] = ngram\n",
    "                    num_tokens += 1\n",
    "            this_doc_ngrams.append(ngramtoi[str(ngram)])\n",
    "            m += 1\n",
    "\n",
    "    ngram_counter = Counter(this_doc_ngrams)\n",
    "    j_indices.extend(ngram_counter.keys())\n",
    "    values.extend(ngram_counter.values())\n",
    "    indptr.append(len(j_indices))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using dictionaries to convert between indices and strings (in this case, our n-grams) is a common & useful approach!  Here, we have `itongram` (index to n-gram) and `ngramtoi` (n-gram to index)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 373,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_ngram_doc_matrix = scipy.sparse.csr_matrix((values, j_indices, indptr),\n",
    "                                   shape=(len(indptr) - 1, len(ngramtoi)),\n",
    "                                   dtype=int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 374,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x260402 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 678912 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 374,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ngram_doc_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Looking at our data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(260428, 260428)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(ngramtoi), len(itongram)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([637,   0,  59])"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[20005]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20005"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ngramtoi[str(np.array([637,   0,  59]))]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 189, 1301])"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[100000]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('nothing', 'changes')"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[189], v[1301]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([63, 48])"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[100010]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('has', 'an')"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[63], v[48]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([94, 36, 84])"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[6116]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('does', \"n't\", 'even')"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[94], v[36], v[84]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([190,  62, 935])"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[6119]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('look', 'her', 'usual')"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[190], v[62], v[935]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 805,   11, 1202])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "itongram[80000]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('business', 'and', 'political')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v[805], v[11], v[1202]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create valid matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 375,
   "metadata": {},
   "outputs": [],
   "source": [
    "j_indices = []\n",
    "indptr = []\n",
    "values = []\n",
    "indptr.append(0)\n",
    "\n",
    "for i, doc in enumerate(movie_reviews.valid.x):\n",
    "    feature_counter = Counter(doc.data)\n",
    "    j_indices.extend(feature_counter.keys())\n",
    "    values.extend(feature_counter.values())\n",
    "    this_doc_ngrams = list()\n",
    "\n",
    "    m = 0\n",
    "    for n in range(min_n, max_n + 1):\n",
    "        for k in range(vocab_len - n + 1):\n",
    "            ngram = doc.data[k: k + n]\n",
    "            if str(ngram) in ngramtoi:\n",
    "                this_doc_ngrams.append(ngramtoi[str(ngram)])\n",
    "            m += 1\n",
    "\n",
    "    ngram_counter = Counter(this_doc_ngrams)\n",
    "    j_indices.extend(ngram_counter.keys())\n",
    "    values.extend(ngram_counter.values())\n",
    "    indptr.append(len(j_indices))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 376,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_ngram_doc_matrix = scipy.sparse.csr_matrix((values, j_indices, indptr),\n",
    "                                   shape=(len(indptr) - 1, len(ngramtoi)),\n",
    "                                   dtype=int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 377,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<200x260402 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 121597 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 377,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "valid_ngram_doc_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 378,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x260402 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 678912 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 378,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ngram_doc_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [],
   "source": [
    "scipy.sparse.save_npz(\"train_ngram_matrix.npz\", train_ngram_doc_matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [],
   "source": [
    "scipy.sparse.save_npz(\"valid_ngram_matrix.npz\", valid_ngram_doc_matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 141,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('itongram.pickle', 'wb') as handle:\n",
    "    pickle.dump(itongram, handle, protocol=pickle.HIGHEST_PROTOCOL)\n",
    "    \n",
    "with open('ngramtoi.pickle', 'wb') as handle:\n",
    "    pickle.dump(itongram, handle, protocol=pickle.HIGHEST_PROTOCOL)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "### Load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "train_ngram_doc_matrix = scipy.sparse.load_npz(\"train_ngram_matrix.npz\")\n",
    "valid_ngram_doc_matrix = scipy.sparse.load_npz(\"valid_ngram_matrix.npz\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "hidden": true
   },
   "outputs": [],
   "source": [
    "with open('itongram.pickle', 'rb') as handle:\n",
    "    b = pickle.load(handle)\n",
    "    \n",
    "with open('ngramtoi.pickle', 'rb') as handle:\n",
    "    b = pickle.load(handle)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 379,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=train_ngram_doc_matrix\n",
    "y=movie_reviews.train.y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 380,
   "metadata": {},
   "outputs": [],
   "source": [
    "positive = y.c2i['positive']\n",
    "negative = y.c2i['negative']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 381,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x260402 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 678912 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 381,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 382,
   "metadata": {},
   "outputs": [],
   "source": [
    "k=260428"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 383,
   "metadata": {},
   "outputs": [],
   "source": [
    "pos = (y.items == positive)[:k]\n",
    "neg = (y.items == negative)[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 384,
   "metadata": {},
   "outputs": [],
   "source": [
    "xx = x[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 385,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_labels = [o == positive for o in movie_reviews.valid.y.items]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 386,
   "metadata": {},
   "outputs": [],
   "source": [
    "p0 = np.squeeze(np.array(xx[neg].sum(0)))\n",
    "p1 = np.squeeze(np.array(xx[pos].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 387,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 388,
   "metadata": {},
   "outputs": [],
   "source": [
    "r = np.log(pr1/pr0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 389,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 390,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-0.08505123261815539"
      ]
     },
     "execution_count": 390,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 391,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.47875, 0.52125)"
      ]
     },
     "execution_count": 391,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(y.items==positive).mean(), (y.items==negative).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 392,
   "metadata": {},
   "outputs": [],
   "source": [
    "pre_preds = valid_ngram_doc_matrix @ r.T + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 393,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 110.972709,   39.540612,    1.138566,   14.709707, ...,   81.056242,   -5.947489, -152.217182,  120.186321])"
      ]
     },
     "execution_count": 393,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pre_preds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 394,
   "metadata": {},
   "outputs": [],
   "source": [
    "preds = pre_preds.T>0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 395,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True,  True,  True,  True, False,  True,  True, False,  True, False])"
      ]
     },
     "execution_count": 395,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "preds[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 396,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_labels = [o == positive for o in movie_reviews.valid.y.items]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 397,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.76"
      ]
     },
     "execution_count": 397,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(preds == valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Binarized Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 398,
   "metadata": {},
   "outputs": [],
   "source": [
    "trn_x_ngram_sgn = train_ngram_doc_matrix.sign()\n",
    "val_x_ngram_sgn = valid_ngram_doc_matrix.sign()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 399,
   "metadata": {},
   "outputs": [],
   "source": [
    "xx = trn_x_ngram_sgn[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 400,
   "metadata": {},
   "outputs": [],
   "source": [
    "p0 = np.squeeze(np.array(xx[neg].sum(0)))\n",
    "p1 = np.squeeze(np.array(xx[pos].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 401,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 403,
   "metadata": {},
   "outputs": [],
   "source": [
    "r = np.log(pr1/pr0)\n",
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean())\n",
    "\n",
    "pre_preds = val_x_ngram_sgn @ r.T + b\n",
    "preds = pre_preds.T>0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 404,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.735"
      ]
     },
     "execution_count": 404,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(preds==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Logistic Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we fit regularized logistic regression where the features are the trigrams."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 405,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LogisticRegression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### use CountVectorizer to compare"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 406,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_extraction.text import CountVectorizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 407,
   "metadata": {},
   "outputs": [],
   "source": [
    "veczr = CountVectorizer(ngram_range=(1,3), preprocessor=noop, tokenizer=noop, max_features=800000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 408,
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = movie_reviews.train.x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 409,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_words = [[docs.vocab.itos[o] for o in doc.data] for doc in movie_reviews.train.x]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 410,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_words = [[docs.vocab.itos[o] for o in doc.data] for doc in movie_reviews.valid.x]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 411,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.22 s, sys: 8 ms, total: 1.22 s\n",
      "Wall time: 1.22 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "train_ngram_doc = veczr.fit_transform(train_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 412,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<800x260401 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 565699 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 412,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ngram_doc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 414,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'xxbos': 235245,\n",
       " 'xxmaj': 235619,\n",
       " 'un': 217541,\n",
       " '-': 14669,\n",
       " 'xxunk': 247983,\n",
       " 'believable': 50437,\n",
       " '!': 593,\n",
       " 'meg': 134464,\n",
       " 'ryan': 171981,\n",
       " 'does': 72638,\n",
       " \"n't\": 141217,\n",
       " 'even': 78300,\n",
       " 'look': 129031,\n",
       " 'her': 101696,\n",
       " 'usual': 219431,\n",
       " 'lovable': 129884,\n",
       " 'self': 175890,\n",
       " 'in': 110078,\n",
       " 'this': 206648,\n",
       " ',': 8808,\n",
       " 'which': 228228,\n",
       " 'normally': 145208,\n",
       " 'makes': 131572,\n",
       " 'me': 133672,\n",
       " 'forgive': 88683,\n",
       " 'shallow': 177184,\n",
       " 'acting': 27693,\n",
       " '.': 16845,\n",
       " 'hard': 97877,\n",
       " 'to': 210394,\n",
       " 'believe': 50474,\n",
       " 'she': 177332,\n",
       " 'was': 222339,\n",
       " 'the': 193825,\n",
       " 'producer': 164509,\n",
       " 'on': 152345,\n",
       " 'dog': 72943,\n",
       " 'plus': 162153,\n",
       " 'kevin': 122626,\n",
       " 'kline': 123483,\n",
       " ':': 20369,\n",
       " 'what': 226885,\n",
       " 'kind': 123253,\n",
       " 'of': 147538,\n",
       " 'suicide': 188380,\n",
       " 'trip': 215838,\n",
       " 'has': 98145,\n",
       " 'his': 103548,\n",
       " 'career': 58706,\n",
       " 'been': 49251,\n",
       " '?': 20997,\n",
       " '...': 18350,\n",
       " 'finally': 85389,\n",
       " 'directed': 71229,\n",
       " 'by': 56573,\n",
       " 'guy': 96432,\n",
       " 'who': 229053,\n",
       " 'did': 70485,\n",
       " 'big': 51612,\n",
       " 'must': 140433,\n",
       " 'be': 47429,\n",
       " 'a': 21285,\n",
       " 'replay': 169637,\n",
       " 'jonestown': 121196,\n",
       " 'hollywood': 105205,\n",
       " 'style': 187631,\n",
       " 'xxbos xxmaj': 235387,\n",
       " 'xxmaj un': 246414,\n",
       " 'un -': 217542,\n",
       " '- xxunk': 16431,\n",
       " 'xxunk -': 248730,\n",
       " '- believable': 14857,\n",
       " 'believable !': 50438,\n",
       " '! xxmaj': 756,\n",
       " 'xxmaj meg': 242214,\n",
       " 'meg xxmaj': 134469,\n",
       " 'xxmaj ryan': 244169,\n",
       " 'ryan does': 171990,\n",
       " \"does n't\": 72770,\n",
       " \"n't even\": 141546,\n",
       " 'even look': 78540,\n",
       " 'look her': 129116,\n",
       " 'her usual': 102342,\n",
       " 'usual xxunk': 219463,\n",
       " 'xxunk lovable': 252472,\n",
       " 'lovable self': 129893,\n",
       " 'self in': 175915,\n",
       " 'in this': 111802,\n",
       " 'this ,': 206667,\n",
       " ', which': 13819,\n",
       " 'which normally': 228500,\n",
       " 'normally makes': 145211,\n",
       " 'makes me': 131651,\n",
       " 'me forgive': 133807,\n",
       " 'forgive her': 88684,\n",
       " 'her shallow': 102248,\n",
       " 'shallow xxunk': 177199,\n",
       " 'xxunk acting': 249152,\n",
       " 'acting xxunk': 27935,\n",
       " 'xxunk .': 248830,\n",
       " '. xxmaj': 17378,\n",
       " 'xxmaj hard': 239935,\n",
       " 'hard to': 97933,\n",
       " 'to believe': 210927,\n",
       " 'believe she': 50543,\n",
       " 'she was': 177776,\n",
       " 'was the': 223713,\n",
       " 'the producer': 199567,\n",
       " 'producer on': 164521,\n",
       " 'on this': 153116,\n",
       " 'this dog': 206987,\n",
       " 'dog .': 72944,\n",
       " 'xxmaj plus': 243544,\n",
       " 'plus xxmaj': 162173,\n",
       " 'xxmaj kevin': 241367,\n",
       " 'kevin xxmaj': 122631,\n",
       " 'xxmaj kline': 241463,\n",
       " 'kline :': 123489,\n",
       " ': what': 20599,\n",
       " 'what kind': 227138,\n",
       " 'kind of': 123276,\n",
       " 'of suicide': 149900,\n",
       " 'suicide trip': 188402,\n",
       " 'trip has': 215849,\n",
       " 'has his': 98415,\n",
       " 'his career': 103726,\n",
       " 'career been': 58722,\n",
       " 'been on': 49462,\n",
       " 'on ?': 152394,\n",
       " '? xxmaj': 21121,\n",
       " 'xxmaj xxunk': 247340,\n",
       " 'xxunk ...': 248876,\n",
       " '... xxmaj': 18634,\n",
       " 'xxunk !': 247988,\n",
       " '! !': 608,\n",
       " 'xxmaj finally': 239085,\n",
       " 'finally this': 85451,\n",
       " 'this was': 208191,\n",
       " 'was directed': 222794,\n",
       " 'directed by': 71242,\n",
       " 'by the': 56992,\n",
       " 'the guy': 197105,\n",
       " 'guy who': 96523,\n",
       " 'who did': 229250,\n",
       " 'did xxmaj': 70760,\n",
       " 'xxmaj big': 236752,\n",
       " 'big xxmaj': 51762,\n",
       " 'xxunk ?': 249000,\n",
       " 'xxmaj must': 242544,\n",
       " 'must be': 140446,\n",
       " 'be a': 47474,\n",
       " 'a replay': 24656,\n",
       " 'replay of': 169640,\n",
       " 'of xxmaj': 150935,\n",
       " 'xxmaj jonestown': 241169,\n",
       " 'jonestown -': 121197,\n",
       " '- hollywood': 15348,\n",
       " 'hollywood style': 105278,\n",
       " 'style .': 187642,\n",
       " 'xxbos xxmaj un': 235573,\n",
       " 'xxmaj un -': 246415,\n",
       " 'un - xxunk': 217545,\n",
       " '- xxunk -': 16437,\n",
       " 'xxunk - believable': 248740,\n",
       " '- believable !': 14858,\n",
       " 'believable ! xxmaj': 50439,\n",
       " '! xxmaj meg': 813,\n",
       " 'xxmaj meg xxmaj': 242217,\n",
       " 'meg xxmaj ryan': 134471,\n",
       " 'xxmaj ryan does': 244174,\n",
       " \"ryan does n't\": 171991,\n",
       " \"does n't even\": 72785,\n",
       " \"n't even look\": 141562,\n",
       " 'even look her': 78542,\n",
       " 'look her usual': 129117,\n",
       " 'her usual xxunk': 102344,\n",
       " 'usual xxunk lovable': 219466,\n",
       " 'xxunk lovable self': 252473,\n",
       " 'lovable self in': 129894,\n",
       " 'self in this': 175916,\n",
       " 'in this ,': 111804,\n",
       " 'this , which': 206693,\n",
       " ', which normally': 13851,\n",
       " 'which normally makes': 228501,\n",
       " 'normally makes me': 145212,\n",
       " 'makes me forgive': 131655,\n",
       " 'me forgive her': 133808,\n",
       " 'forgive her shallow': 88685,\n",
       " 'her shallow xxunk': 102249,\n",
       " 'shallow xxunk acting': 177200,\n",
       " 'xxunk acting xxunk': 249154,\n",
       " 'acting xxunk .': 27936,\n",
       " 'xxunk . xxmaj': 248864,\n",
       " '. xxmaj hard': 17676,\n",
       " 'xxmaj hard to': 239936,\n",
       " 'hard to believe': 97940,\n",
       " 'to believe she': 210934,\n",
       " 'believe she was': 50544,\n",
       " 'she was the': 177809,\n",
       " 'was the producer': 223755,\n",
       " 'the producer on': 199569,\n",
       " 'producer on this': 164522,\n",
       " 'on this dog': 153121,\n",
       " 'this dog .': 206988,\n",
       " 'dog . xxmaj': 72946,\n",
       " '. xxmaj plus': 17920,\n",
       " 'xxmaj plus xxmaj': 243548,\n",
       " 'plus xxmaj kevin': 162176,\n",
       " 'xxmaj kevin xxmaj': 241370,\n",
       " 'kevin xxmaj kline': 122633,\n",
       " 'xxmaj kline :': 241466,\n",
       " 'kline : what': 123490,\n",
       " ': what kind': 20600,\n",
       " 'what kind of': 227139,\n",
       " 'kind of suicide': 123325,\n",
       " 'of suicide trip': 149902,\n",
       " 'suicide trip has': 188403,\n",
       " 'trip has his': 215850,\n",
       " 'has his career': 98417,\n",
       " 'his career been': 103730,\n",
       " 'career been on': 58723,\n",
       " 'been on ?': 49463,\n",
       " 'on ? xxmaj': 152395,\n",
       " '? xxmaj xxunk': 21220,\n",
       " 'xxmaj xxunk ...': 247355,\n",
       " 'xxunk ... xxmaj': 248895,\n",
       " '... xxmaj xxunk': 18669,\n",
       " 'xxmaj xxunk !': 247341,\n",
       " 'xxunk ! !': 247990,\n",
       " '! ! !': 610,\n",
       " '! ! xxmaj': 615,\n",
       " '! xxmaj finally': 793,\n",
       " 'xxmaj finally this': 239090,\n",
       " 'finally this was': 85452,\n",
       " 'this was directed': 208199,\n",
       " 'was directed by': 222795,\n",
       " 'directed by the': 71243,\n",
       " 'by the guy': 57034,\n",
       " 'the guy who': 197110,\n",
       " 'guy who did': 96527,\n",
       " 'who did xxmaj': 229253,\n",
       " 'did xxmaj big': 70762,\n",
       " 'xxmaj big xxmaj': 236757,\n",
       " 'big xxmaj xxunk': 51769,\n",
       " 'xxmaj xxunk ?': 247369,\n",
       " 'xxunk ? xxmaj': 249011,\n",
       " '? xxmaj must': 21172,\n",
       " 'xxmaj must be': 242545,\n",
       " 'must be a': 140448,\n",
       " 'be a replay': 47519,\n",
       " 'a replay of': 24657,\n",
       " 'replay of xxmaj': 169642,\n",
       " 'of xxmaj jonestown': 151078,\n",
       " 'xxmaj jonestown -': 241170,\n",
       " 'jonestown - hollywood': 121198,\n",
       " '- hollywood style': 15349,\n",
       " 'hollywood style .': 105279,\n",
       " 'style . xxmaj': 187643,\n",
       " '. xxmaj xxunk': 18197,\n",
       " 'is': 114388,\n",
       " 'extremely': 80780,\n",
       " 'well': 225746,\n",
       " 'made': 130666,\n",
       " 'film': 83839,\n",
       " 'script': 174300,\n",
       " 'and': 33959,\n",
       " 'camera': 57738,\n",
       " 'work': 233513,\n",
       " 'are': 41025,\n",
       " 'all': 30474,\n",
       " 'first': 85911,\n",
       " 'rate': 166635,\n",
       " 'music': 140267,\n",
       " 'good': 94167,\n",
       " 'too': 214437,\n",
       " 'though': 208639,\n",
       " 'it': 117573,\n",
       " 'mostly': 137870,\n",
       " 'early': 74996,\n",
       " 'when': 227487,\n",
       " 'things': 206104,\n",
       " 'still': 185875,\n",
       " 'relatively': 168987,\n",
       " 'there': 204279,\n",
       " 'no': 144389,\n",
       " 'really': 167534,\n",
       " 'cast': 59090,\n",
       " 'several': 176885,\n",
       " 'faces': 81066,\n",
       " 'will': 230407,\n",
       " 'familiar': 81645,\n",
       " 'entire': 77496,\n",
       " 'an': 33100,\n",
       " 'excellent': 79815,\n",
       " 'job': 120769,\n",
       " 'with': 231200,\n",
       " '\\n \\n ': 0,\n",
       " 'but': 55233,\n",
       " 'watch': 224142,\n",
       " 'because': 48827,\n",
       " 'end': 76351,\n",
       " 'situation': 180264,\n",
       " 'like': 126924,\n",
       " 'one': 153423,\n",
       " 'presented': 163577,\n",
       " 'now': 146760,\n",
       " 'blame': 52362,\n",
       " 'british': 54359,\n",
       " 'for': 87111,\n",
       " 'setting': 176810,\n",
       " 'hindus': 103492,\n",
       " 'muslims': 140422,\n",
       " 'against': 29872,\n",
       " 'each': 74800,\n",
       " 'other': 156127,\n",
       " 'then': 203901,\n",
       " 'them': 203472,\n",
       " 'into': 113706,\n",
       " 'two': 216877,\n",
       " 'countries': 66021,\n",
       " 'some': 182093,\n",
       " 'merit': 134952,\n",
       " 'view': 220903,\n",
       " \"'s\": 4219,\n",
       " 'also': 31802,\n",
       " 'true': 215952,\n",
       " 'that': 191543,\n",
       " 'forced': 88485,\n",
       " 'region': 168815,\n",
       " 'as': 42811,\n",
       " 'they': 204967,\n",
       " 'around': 42453,\n",
       " 'time': 209711,\n",
       " 'partition': 158823,\n",
       " 'seems': 175485,\n",
       " 'more': 136861,\n",
       " 'likely': 127658,\n",
       " 'simply': 179677,\n",
       " 'saw': 172810,\n",
       " 'between': 51345,\n",
       " 'were': 226152,\n",
       " 'clever': 62399,\n",
       " 'enough': 77149,\n",
       " 'exploit': 80571,\n",
       " 'their': 202859,\n",
       " 'own': 157786,\n",
       " 'ends': 76709,\n",
       " 'result': 169941,\n",
       " 'much': 139743,\n",
       " 'cruelty': 67253,\n",
       " 'inhumanity': 112841,\n",
       " 'very': 220028,\n",
       " 'unpleasant': 218279,\n",
       " 'remember': 169309,\n",
       " 'see': 174840,\n",
       " 'screen': 174101,\n",
       " 'never': 143379,\n",
       " 'painted': 158250,\n",
       " 'black': 52211,\n",
       " 'white': 228967,\n",
       " 'case': 58985,\n",
       " 'both': 53392,\n",
       " 'sides': 179401,\n",
       " 'hope': 105534,\n",
       " 'change': 59933,\n",
       " 'younger': 259694,\n",
       " 'generation': 91777,\n",
       " 'redemption': 168609,\n",
       " 'sort': 183622,\n",
       " 'make': 131252,\n",
       " 'choice': 61352,\n",
       " 'man': 131972,\n",
       " 'ruined': 171670,\n",
       " 'life': 126539,\n",
       " 'truly': 216095,\n",
       " 'loved': 130104,\n",
       " 'family': 81676,\n",
       " 'later': 124790,\n",
       " 'come': 63112,\n",
       " 'looking': 129249,\n",
       " 'point': 162209,\n",
       " 'without': 232583,\n",
       " 'great': 95376,\n",
       " 'pain': 158154,\n",
       " 'carries': 58869,\n",
       " 'message': 135015,\n",
       " 'have': 98847,\n",
       " 'grave': 95342,\n",
       " 'can': 57902,\n",
       " 'caring': 58782,\n",
       " 'people': 159402,\n",
       " 'reality': 167435,\n",
       " 'wrenching': 234830,\n",
       " 'since': 179847,\n",
       " 'real': 167146,\n",
       " 'across': 27577,\n",
       " 'india': 112505,\n",
       " '/': 18693,\n",
       " 'pakistan': 158299,\n",
       " 'border': 53152,\n",
       " 'sense': 176005,\n",
       " 'similar': 179551,\n",
       " '\"': 885,\n",
       " 'mr': 139656,\n",
       " '&': 2770,\n",
       " 'we': 225032,\n",
       " 'glad': 93403,\n",
       " 'seen': 175612,\n",
       " 'resolution': 169789,\n",
       " 'if': 109113,\n",
       " 'xxup': 256448,\n",
       " 'uk': 217458,\n",
       " 'us': 219019,\n",
       " 'could': 65644,\n",
       " 'deal': 68618,\n",
       " 'racism': 166252,\n",
       " 'would': 234332,\n",
       " 'certainly': 59737,\n",
       " 'better': 51101,\n",
       " 'off': 151385,\n",
       " 'xxmaj this': 245994,\n",
       " 'this is': 207344,\n",
       " 'is a': 114476,\n",
       " 'a extremely': 22470,\n",
       " 'extremely well': 80833,\n",
       " 'well -': 225791,\n",
       " '- made': 15557,\n",
       " 'made film': 130775,\n",
       " 'film .': 83997,\n",
       " 'xxmaj the': 245427,\n",
       " 'the acting': 194076,\n",
       " 'acting ,': 27710,\n",
       " ', script': 12382,\n",
       " 'script and': 174330,\n",
       " 'and camera': 34633,\n",
       " 'camera -': 57749,\n",
       " '- work': 16333,\n",
       " 'work are': 233548,\n",
       " 'are all': 41108,\n",
       " 'all first': 30719,\n",
       " 'first -': 85933,\n",
       " '- rate': 15858,\n",
       " 'rate .': 166640,\n",
       " 'the music': 198575,\n",
       " 'music is': 140331,\n",
       " 'is good': 115473,\n",
       " 'good ,': 94186,\n",
       " ', too': 13460,\n",
       " 'too ,': 214440,\n",
       " ', though': 13373,\n",
       " 'though it': 208734,\n",
       " 'it is': 118593,\n",
       " 'is mostly': 115911,\n",
       " 'mostly early': 137897,\n",
       " 'early in': 75040,\n",
       " 'in the': 111429,\n",
       " 'the film': 196399,\n",
       " 'film ,': 83916,\n",
       " ', when': 13766,\n",
       " 'when things': 227807,\n",
       " 'things are': 206134,\n",
       " 'are still': 42003,\n",
       " 'still relatively': 186064,\n",
       " 'relatively xxunk': 168998,\n",
       " 'xxmaj there': 245886,\n",
       " 'there are': 204362,\n",
       " 'are no': 41703,\n",
       " 'no really': 144777,\n",
       " 'really xxunk': 168073,\n",
       " 'xxunk in': 251885,\n",
       " 'the cast': 194895,\n",
       " 'cast ,': 59099,\n",
       " 'though several': 208754,\n",
       " 'several faces': 176894,\n",
       " 'faces will': 81082,\n",
       " 'will be': 230442,\n",
       " 'be familiar': 47794,\n",
       " 'familiar .': 81649,\n",
       " 'the entire': 196079,\n",
       " 'entire cast': 77501,\n",
       " 'cast does': 59149,\n",
       " 'does an': 72668,\n",
       " 'an excellent': 33479,\n",
       " 'excellent job': 79860,\n",
       " 'job with': 120843,\n",
       " 'with the': 232107,\n",
       " 'the script': 200200,\n",
       " 'script .': 174322,\n",
       " '. \\n \\n ': 16846,\n",
       " '\\n \\n  xxmaj': 201,\n",
       " 'xxmaj but': 237156,\n",
       " 'but it': 55712,\n",
       " 'is hard': 115506,\n",
       " 'to watch': 213697,\n",
       " 'watch ,': 224148,\n",
       " ', because': 9683,\n",
       " 'because there': 48997,\n",
       " 'there is': 204470,\n",
       " 'is no': 116027,\n",
       " 'no good': 144577,\n",
       " 'good end': 94348,\n",
       " 'end to': 76492,\n",
       " 'to a': 210460,\n",
       " 'a situation': 25006,\n",
       " 'situation like': 180285,\n",
       " 'like the': 127344,\n",
       " 'the one': 198859,\n",
       " 'one presented': 153923,\n",
       " 'presented .': 163580,\n",
       " 'xxmaj it': 240758,\n",
       " 'is now': 116143,\n",
       " 'now xxunk': 146943,\n",
       " 'xxunk to': 254882,\n",
       " 'to blame': 210953,\n",
       " 'blame the': 52371,\n",
       " 'the xxmaj': 201976,\n",
       " 'xxmaj british': 237029,\n",
       " 'british for': 54380,\n",
       " 'for setting': 87910,\n",
       " 'setting xxmaj': 176836,\n",
       " 'xxmaj hindus': 240216,\n",
       " 'hindus and': 103493,\n",
       " 'and xxmaj': 38626,\n",
       " 'xxmaj muslims': 242539,\n",
       " 'muslims against': 140426,\n",
       " 'against each': 29885,\n",
       " 'each other': 74866,\n",
       " 'other ,': 156138,\n",
       " ', and': 9218,\n",
       " 'and then': 37939,\n",
       " 'then xxunk': 204237,\n",
       " 'xxunk xxunk': 256140,\n",
       " 'xxunk them': 254721,\n",
       " 'them into': 203630,\n",
       " 'into two': 114027,\n",
       " 'two countries': 216949,\n",
       " 'countries .': 66022,\n",
       " 'is some': 116671,\n",
       " 'some merit': 182403,\n",
       " 'merit in': 134955,\n",
       " 'this view': 208179,\n",
       " 'view ,': 220908,\n",
       " ', but': 9824,\n",
       " \"it 's\": 117610,\n",
       " \"'s also\": 4429,\n",
       " 'also true': 32196,\n",
       " 'true that': 216052,\n",
       " 'that no': 192798,\n",
       " 'no one': 144700,\n",
       " 'one forced': 153682,\n",
       " 'forced xxmaj': 88517,\n",
       " 'muslims in': 140430,\n",
       " 'the region': 199789,\n",
       " 'region to': 168820,\n",
       " 'to xxunk': 213936,\n",
       " 'xxunk each': 250866,\n",
       " 'other as': 156178,\n",
       " 'as they': 43790,\n",
       " 'they did': 205251,\n",
       " 'did around': 70522,\n",
       " 'around the': 42557,\n",
       " 'the time': 201168,\n",
       " 'time of': 209939,\n",
       " 'of partition': 149450,\n",
       " 'partition .': 158824,\n",
       " 'it seems': 119112,\n",
       " 'seems more': 175532,\n",
       " 'more likely': 137171,\n",
       " 'likely that': 127663,\n",
       " 'that the': 193183,\n",
       " 'british simply': 54388,\n",
       " 'simply saw': 179788,\n",
       " 'saw the': 172867,\n",
       " 'the xxunk': 202357,\n",
       " 'xxunk between': 250039,\n",
       " 'between the': 51422,\n",
       " 'xxunk and': 249319,\n",
       " 'and were': 38456,\n",
       " 'were clever': 226268,\n",
       " 'clever enough': 62419,\n",
       " 'enough to': 77250,\n",
       " 'to exploit': 211477,\n",
       " 'exploit them': 80574,\n",
       " 'them to': 203708,\n",
       " 'to their': 213505,\n",
       " 'their own': 203225,\n",
       " 'own ends': 157849,\n",
       " 'ends .': 76714,\n",
       " 'the result': 199865,\n",
       " 'result is': 169950,\n",
       " 'is that': 116818,\n",
       " 'that there': 193302,\n",
       " 'is much': 115922,\n",
       " 'much cruelty': 139835,\n",
       " 'cruelty and': 67256,\n",
       " 'and inhumanity': 36008,\n",
       " 'inhumanity in': 112844,\n",
       " 'the situation': 200490,\n",
       " 'situation and': 180273,\n",
       " 'and this': 38049,\n",
       " 'is very': 117159,\n",
       " 'very unpleasant': 220539,\n",
       " 'unpleasant to': 218286,\n",
       " 'to remember': 212726,\n",
       " 'remember and': 169322,\n",
       " 'and to': 38124,\n",
       " 'to see': 212884,\n",
       " 'see on': 175066,\n",
       " 'on the': 152927,\n",
       " 'the screen': 200165,\n",
       " 'screen .': 174117,\n",
       " 'is never': 116013,\n",
       " 'never painted': 143594,\n",
       " 'painted as': 158255,\n",
       " 'as a': 42836,\n",
       " 'a black': 21636,\n",
       " 'black -': 52220,\n",
       " '- and': 14769,\n",
       " 'and -': 34009,\n",
       " '- white': 16300,\n",
       " 'white case': 228982,\n",
       " 'case .': 59002,\n",
       " 'is xxunk': 117387,\n",
       " 'and xxunk': 38901,\n",
       " 'xxunk on': 253106,\n",
       " 'on both': 152543,\n",
       " 'both sides': 53519,\n",
       " 'sides ,': 179402,\n",
       " 'and also': 34261,\n",
       " 'also the': 32167,\n",
       " 'the hope': 197270,\n",
       " 'hope for': 105552,\n",
       " 'for change': 87380,\n",
       " 'change in': 59950,\n",
       " 'the younger': 202778,\n",
       " 'younger generation': 259701,\n",
       " 'generation .': 91783,\n",
       " 'is redemption': 116438,\n",
       " 'redemption of': 168616,\n",
       " 'of a': 147636,\n",
       " 'a sort': 25109,\n",
       " 'sort ,': 183623,\n",
       " ', in': 11128,\n",
       " 'the end': 196001,\n",
       " 'end ,': 76358,\n",
       " 'when xxmaj': 227831,\n",
       " 'xxunk has': 251545,\n",
       " 'has to': 98656,\n",
       " 'to make': 212219,\n",
       " 'make a': 131263,\n",
       " 'a hard': 23147,\n",
       " 'hard choice': 97903,\n",
       " 'choice between': 61360,\n",
       " 'between a': 51358,\n",
       " 'a man': 23695,\n",
       " 'man who': 132176,\n",
       " 'who has': 229355,\n",
       " 'has ruined': 98579,\n",
       " 'ruined her': 171678,\n",
       " 'her life': 102082,\n",
       " 'life ,': 126556,\n",
       " 'but also': 55315,\n",
       " 'also truly': 32198,\n",
       " 'truly loved': 216140,\n",
       " 'loved her': 130113,\n",
       " 'her ,': 101714,\n",
       " 'and her': 35725,\n",
       " 'her family': 101954,\n",
       " 'family which': 81823,\n",
       " 'which has': 228349,\n",
       " 'has xxunk': 98702,\n",
       " 'xxunk her': 251616,\n",
       " ', then': 13182,\n",
       " 'then later': 204101,\n",
       " 'later come': 124832,\n",
       " 'come looking': 63173,\n",
       " 'looking for': 129282,\n",
       " 'for her': 87517,\n",
       " 'her .': 101732,\n",
       " 'but by': 55387,\n",
       " 'by that': 56989,\n",
       " 'that point': 192920,\n",
       " 'point ,': 162212,\n",
       " ', she': 12453,\n",
       " 'she has': 177530,\n",
       " 'has no': 98504,\n",
       " 'no xxunk': 144906,\n",
       " 'xxunk that': 254401,\n",
       " 'that is': 192462,\n",
       " 'is without': 117292,\n",
       " 'without great': 232660,\n",
       " 'great pain': 95613,\n",
       " 'pain for': 158170,\n",
       " 'this film': 207054,\n",
       " 'film carries': 84164,\n",
       " 'carries the': 58873,\n",
       " 'the message': 198187,\n",
       " 'message that': 135052,\n",
       " 'that both': 191889,\n",
       " 'both xxmaj': 53555,\n",
       " 'muslims and': 140428,\n",
       " 'hindus have': 103495,\n",
       " 'have their': 99579,\n",
       " 'their grave': 203092,\n",
       " 'grave xxunk': 95357,\n",
       " 'xxunk ,': 248429,\n",
       " 'also that': 32164,\n",
       " 'both can': 53423,\n",
       " 'can be': 57953,\n",
       " 'be xxunk': 48432,\n",
       " 'and caring': 34653,\n",
       " 'caring people': 58792,\n",
       " 'people .': 159438,\n",
       " 'the reality': 199735,\n",
       " 'reality of': 167462,\n",
       " 'partition makes': 158828,\n",
       " 'makes that': 131687,\n",
       " 'that xxunk': 193725,\n",
       " 'xxunk all': 249241,\n",
       " 'all the': 31003,\n",
       " 'the more': 198292,\n",
       " 'more wrenching': 137414,\n",
       " 'wrenching ,': 234831,\n",
       " ', since': 12536,\n",
       " 'since there': 179925,\n",
       " 'there can': 204435,\n",
       " 'can never': 58123,\n",
       " 'never be': 143401,\n",
       " 'be real': 48117,\n",
       " 'real xxunk': 167347,\n",
       " 'xxunk across': 249146,\n",
       " 'across the': 27597,\n",
       " 'xxmaj india': 240621,\n",
       " 'india /': 112512,\n",
       " '/ xxmaj': 18915,\n",
       " 'xxmaj pakistan': 243213,\n",
       " 'pakistan border': 158302,\n",
       " 'border .': 53155,\n",
       " 'xxmaj in': 240564,\n",
       " 'in that': 111398,\n",
       " 'that sense': 193043,\n",
       " 'sense ,': 176011,\n",
       " ', it': 11295,\n",
       " 'is similar': 116600,\n",
       " 'similar to': 179583,\n",
       " 'to \"': 210398,\n",
       " '\" xxmaj': 2329,\n",
       " 'xxmaj mr': 242491,\n",
       " 'mr &': 139657,\n",
       " '& xxmaj': 2909,\n",
       " 'xxunk xxmaj': 255692,\n",
       " 'xxunk \"': 248003,\n",
       " '\" .': 1004,\n",
       " ', we': 13687,\n",
       " 'we were': 225359,\n",
       " 'were glad': 226367,\n",
       " 'glad to': 93416,\n",
       " 'to have': 211763,\n",
       " 'have seen': 99454,\n",
       " 'seen the': 175800,\n",
       " ', even': 10434,\n",
       " 'even though': 78686,\n",
       " 'though the': 208765,\n",
       " 'the resolution': 199849,\n",
       " 'resolution was': 169805,\n",
       " 'was xxunk': 223972,\n",
       " 'xxmaj if': 240505,\n",
       " 'if the': 109311,\n",
       " 'the xxup': 202682,\n",
       " 'xxup uk': 257624,\n",
       " 'uk and': 217465,\n",
       " 'and xxup': 39060,\n",
       " 'xxup us': 257637,\n",
       " 'us could': 219071,\n",
       " 'could deal': 65730,\n",
       " 'deal with': 68637,\n",
       " 'with their': 232242,\n",
       " 'own xxunk': 157977,\n",
       " 'xxunk of': 252919,\n",
       " 'of racism': 149579,\n",
       " 'racism with': 166272,\n",
       " 'with this': 232274,\n",
       " 'this kind': 207446,\n",
       " 'of xxunk': 151201,\n",
       " ', they': 13241,\n",
       " 'they would': 205841,\n",
       " 'would certainly': 234439,\n",
       " 'certainly be': 59742,\n",
       " 'be better': 47645,\n",
       " 'better off': 51236,\n",
       " 'off .': 151405,\n",
       " 'xxbos xxmaj this': 235568,\n",
       " 'xxmaj this is': 246034,\n",
       " 'this is a': 207348,\n",
       " 'is a extremely': 114525,\n",
       " 'a extremely well': 22471,\n",
       " 'extremely well -': 80834,\n",
       " 'well - made': 225801,\n",
       " '- made film': 15559,\n",
       " 'made film .': 130777,\n",
       " 'film . xxmaj': 84004,\n",
       " '. xxmaj the': 18078,\n",
       " 'xxmaj the acting': 245437,\n",
       " 'the acting ,': 194078,\n",
       " 'acting , script': 27731,\n",
       " ', script and': 12383,\n",
       " 'script and camera': 174332,\n",
       " 'and camera -': 34634,\n",
       " 'camera - work': 57750,\n",
       " '- work are': 16335,\n",
       " 'work are all': 233549,\n",
       " 'are all first': 41114,\n",
       " 'all first -': 30720,\n",
       " 'first - rate': 85936,\n",
       " '- rate .': 15859,\n",
       " 'rate . xxmaj': 166641,\n",
       " 'xxmaj the music': 245666,\n",
       " 'the music is': 198584,\n",
       " 'music is good': 140334,\n",
       " 'is good ,': 115476,\n",
       " 'good , too': 94203,\n",
       " ', too ,': 13462,\n",
       " 'too , though': 214451,\n",
       " ', though it': 13387,\n",
       " 'though it is': 208738,\n",
       " 'it is mostly': 118663,\n",
       " 'is mostly early': 115916,\n",
       " 'mostly early in': 137898,\n",
       " 'early in the': 75041,\n",
       " 'in the film': 111547,\n",
       " 'the film ,': 196405,\n",
       " 'film , when': 83969,\n",
       " ', when things': 13787,\n",
       " 'when things are': 227808,\n",
       " 'things are still': 206138,\n",
       " 'are still relatively': 42006,\n",
       " 'still relatively xxunk': 186065,\n",
       " 'relatively xxunk .': 168999,\n",
       " '. xxmaj there': 18081,\n",
       " 'xxmaj there are': 245891,\n",
       " 'there are no': 204396,\n",
       " 'are no really': 41714,\n",
       " 'no really xxunk': 144778,\n",
       " 'really xxunk in': 168079,\n",
       " 'xxunk in the': 251957,\n",
       " 'in the cast': 111486,\n",
       " 'the cast ,': 194896,\n",
       " 'cast , though': 59111,\n",
       " ', though several': 13392,\n",
       " 'though several faces': 208755,\n",
       " 'several faces will': 176895,\n",
       " 'faces will be': 81083,\n",
       " 'will be familiar': 230458,\n",
       " 'be familiar .': 47795,\n",
       " 'familiar . xxmaj': 81650,\n",
       " 'xxmaj the entire': 245540,\n",
       " 'the entire cast': 196082,\n",
       " 'entire cast does': 77503,\n",
       " 'cast does an': 59150,\n",
       " 'does an excellent': 72669,\n",
       " 'an excellent job': 33484,\n",
       " 'excellent job with': 79863,\n",
       " 'job with the': 120844,\n",
       " 'with the script': 232219,\n",
       " 'the script .': 200204,\n",
       " 'script . \\n \\n ': 174323,\n",
       " '. \\n \\n  xxmaj': 16880,\n",
       " '\\n \\n  xxmaj but': 256,\n",
       " 'xxmaj but it': 237188,\n",
       " 'but it is': 55729,\n",
       " 'it is hard': 118647,\n",
       " 'is hard to': 115508,\n",
       " 'hard to watch': 97958,\n",
       " 'to watch ,': 213700,\n",
       " 'watch , because': 224149,\n",
       " ', because there': 9696,\n",
       " 'because there is': 49000,\n",
       " 'there is no': 204496,\n",
       " 'is no good': 116036,\n",
       " 'no good end': 144580,\n",
       " 'good end to': 94350,\n",
       " 'end to a': 76493,\n",
       " 'to a situation': 210514,\n",
       " 'a situation like': 25008,\n",
       " 'situation like the': 180286,\n",
       " 'like the one': 127370,\n",
       " 'the one presented': 198874,\n",
       " 'one presented .': 153924,\n",
       " 'presented . xxmaj': 163581,\n",
       " '. xxmaj it': 17723,\n",
       " 'xxmaj it is': 240800,\n",
       " 'it is now': 118672,\n",
       " 'is now xxunk': 116149,\n",
       " 'now xxunk to': 146947,\n",
       " 'xxunk to blame': 254909,\n",
       " 'to blame the': 210955,\n",
       " 'blame the xxmaj': 52374,\n",
       " 'the xxmaj british': 202012,\n",
       " 'xxmaj british for': 237039,\n",
       " 'british for setting': 54381,\n",
       " 'for setting xxmaj': 87911,\n",
       " 'setting xxmaj hindus': 176837,\n",
       " 'xxmaj hindus and': 240217,\n",
       " 'hindus and xxmaj': 103494,\n",
       " 'and xxmaj muslims': 38809,\n",
       " 'xxmaj muslims against': 242541,\n",
       " 'muslims against each': 140427,\n",
       " 'against each other': 29886,\n",
       " 'each other ,': 74868,\n",
       " 'other , and': 156139,\n",
       " ', and then': 9449,\n",
       " 'and then xxunk': 37980,\n",
       " 'then xxunk xxunk': 204248,\n",
       " 'xxunk xxunk them': 256288,\n",
       " 'xxunk them into': 254727,\n",
       " 'them into two': 203633,\n",
       " 'into two countries': 114028,\n",
       " 'two countries .': 216950,\n",
       " 'countries . xxmaj': 66023,\n",
       " 'xxmaj there is': 245894,\n",
       " 'there is some': 204507,\n",
       " 'is some merit': 116675,\n",
       " 'some merit in': 182404,\n",
       " 'merit in this': 134956,\n",
       " 'in this view': 111857,\n",
       " 'this view ,': 208180,\n",
       " 'view , but': 220910,\n",
       " ', but it': 9898,\n",
       " \"but it 's\": 55713,\n",
       " \"it 's also\": 117622,\n",
       " \"'s also true\": 4437,\n",
       " 'also true that': 32197,\n",
       " 'true that no': 216053,\n",
       " 'that no one': 192803,\n",
       " 'no one forced': 144708,\n",
       " 'one forced xxmaj': 153683,\n",
       " 'forced xxmaj hindus': 88518,\n",
       " 'xxmaj muslims in': 242543,\n",
       " 'muslims in the': 140431,\n",
       " 'in the region': 111656,\n",
       " 'the region to': 199790,\n",
       " 'region to xxunk': 168821,\n",
       " 'to xxunk each': 213967,\n",
       " 'xxunk each other': 250870,\n",
       " 'each other as': 74875,\n",
       " 'other as they': 156179,\n",
       " 'as they did': 43796,\n",
       " 'they did around': 205254,\n",
       " 'did around the': 70523,\n",
       " 'around the time': 42568,\n",
       " 'the time of': 201180,\n",
       " 'time of partition': 209941,\n",
       " 'of partition .': 149451,\n",
       " 'partition . xxmaj': 158825,\n",
       " 'xxmaj it seems': 240832,\n",
       " 'it seems more': 119120,\n",
       " 'seems more likely': 175533,\n",
       " 'more likely that': 137173,\n",
       " 'likely that the': 127664,\n",
       " 'that the xxmaj': 193292,\n",
       " 'xxmaj british simply': 237043,\n",
       " 'british simply saw': 54389,\n",
       " 'simply saw the': 179789,\n",
       " 'saw the xxunk': 172876,\n",
       " 'the xxunk between': 202403,\n",
       " 'xxunk between the': 250050,\n",
       " 'between the xxunk': 51448,\n",
       " 'the xxunk and': 202387,\n",
       " 'xxunk and were': 249613,\n",
       " 'and were clever': 38457,\n",
       " 'were clever enough': 226269,\n",
       " 'clever enough to': 62420,\n",
       " 'enough to exploit': 77256,\n",
       " 'to exploit them': 211479,\n",
       " 'exploit them to': 80575,\n",
       " 'them to their': 203720,\n",
       " 'to their own': 213515,\n",
       " 'their own ends': 203232,\n",
       " 'own ends .': 157850,\n",
       " 'ends . \\n \\n ': 76715,\n",
       " '\\n \\n  xxmaj the': 500,\n",
       " 'xxmaj the result': 245734,\n",
       " 'the result is': 199866,\n",
       " 'result is that': 169954,\n",
       " 'is that there': 116849,\n",
       " 'that there is': 193305,\n",
       " 'there is much': 204492,\n",
       " 'is much cruelty': 115924,\n",
       " 'much cruelty and': 139836,\n",
       " 'cruelty and inhumanity': 67257,\n",
       " 'and inhumanity in': 36010,\n",
       " 'inhumanity in the': 112845,\n",
       " 'in the situation': 111689,\n",
       " 'the situation and': 200494,\n",
       " 'situation and this': 180274,\n",
       " 'and this is': 38058,\n",
       " 'this is very': 207419,\n",
       " 'is very unpleasant': 117194,\n",
       " 'very unpleasant to': 220540,\n",
       " 'unpleasant to remember': 218287,\n",
       " ...}"
      ]
     },
     "execution_count": 414,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "veczr.vocabulary_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 417,
   "metadata": {},
   "outputs": [],
   "source": [
    "val_ngram_doc = veczr.transform(valid_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 418,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<200x260401 sparse matrix of type '<class 'numpy.int64'>'\n",
       "\twith 93549 stored elements in Compressed Sparse Row format>"
      ]
     },
     "execution_count": 418,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val_ngram_doc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 419,
   "metadata": {},
   "outputs": [],
   "source": [
    "vocab = veczr.get_feature_names()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 215,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['the room she',\n",
       " 'the room when',\n",
       " 'the room where',\n",
       " 'the rooms',\n",
       " 'the rooms are']"
      ]
     },
     "execution_count": 215,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vocab[200000:200005]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Binarized Naive Bayes, using ngrams from CountVectorizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 415,
   "metadata": {},
   "outputs": [],
   "source": [
    "y=movie_reviews.train.y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C is the inverse of regularization strength; smaller values specify stronger regularization.  Regularized:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 420,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.83"
      ]
     },
     "execution_count": 420,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = LogisticRegression(C=0.1, dual=True)\n",
    "m.fit(train_ngram_doc.sign(), y.items);\n",
    "\n",
    "preds = m.predict(val_ngram_doc.sign())\n",
    "(preds.T==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Not binarized"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 421,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/racheltho/anaconda3/lib/python3.7/site-packages/sklearn/svm/base.py:922: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.\n",
      "  \"the number of iterations.\", ConvergenceWarning)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.78"
      ]
     },
     "execution_count": 421,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = LogisticRegression(C=0.1, dual=True)\n",
    "m.fit(train_ngram_doc, y.items);\n",
    "\n",
    "preds = m.predict(val_ngram_doc)\n",
    "(preds.T==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using my ngrams, binarized:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 236,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LogisticRegression(C=0.1, class_weight=None, dual=True, fit_intercept=True,\n",
       "          intercept_scaling=1, max_iter=100, multi_class='warn',\n",
       "          n_jobs=None, penalty='l2', random_state=None, solver='warn',\n",
       "          tol=0.0001, verbose=0, warm_start=False)"
      ]
     },
     "execution_count": 236,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m2 = LogisticRegression(C=0.1, dual=True)\n",
    "m2.fit(trn_x_ngram_sgn, y.items)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 240,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.83"
      ]
     },
     "execution_count": 240,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "preds = m2.predict(val_x_ngram_sgn)\n",
    "(preds.T==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Worse performance when not binarized.  I manually tried several different C values, and this was the best I found:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 251,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "LogisticRegression(C=0.0001, class_weight=None, dual=True, fit_intercept=True,\n",
       "          intercept_scaling=1, max_iter=50000, multi_class='warn',\n",
       "          n_jobs=None, penalty='l2', random_state=None, solver='warn',\n",
       "          tol=0.0001, verbose=0, warm_start=False)"
      ]
     },
     "execution_count": 251,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m2 = LogisticRegression(C=0.0001, dual=True, max_iter=50000)\n",
    "m2.fit(train_ngram_doc_matrix, y.items)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 252,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.675"
      ]
     },
     "execution_count": 252,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "preds = m2.predict(valid_ngram_doc_matrix)\n",
    "(preds.T==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Log-count ratio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is the $\\text{log-count ratio}$ `r`.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 422,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=train_ngram_doc_matrix.sign()\n",
    "val_x=valid_ngram_doc_matrix.sign()\n",
    "y=movie_reviews.train.y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 423,
   "metadata": {},
   "outputs": [],
   "source": [
    "positive = y.c2i['positive']\n",
    "negative = y.c2i['negative']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 424,
   "metadata": {},
   "outputs": [],
   "source": [
    "k=260428"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 425,
   "metadata": {},
   "outputs": [],
   "source": [
    "pos = (y.items == positive)[:k]\n",
    "neg = (y.items == negative)[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 426,
   "metadata": {},
   "outputs": [],
   "source": [
    "xx = x[:k]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 427,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_labels = [o == positive for o in movie_reviews.valid.y.items]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 428,
   "metadata": {},
   "outputs": [],
   "source": [
    "p0 = np.squeeze(np.array(xx[neg].sum(0)))\n",
    "p1 = np.squeeze(np.array(xx[pos].sum(0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 429,
   "metadata": {},
   "outputs": [],
   "source": [
    "pr1 = (p1+1) / ((y.items==positive).sum() + 1)\n",
    "pr0 = (p0+1) / ((y.items==negative).sum() + 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 430,
   "metadata": {},
   "outputs": [],
   "source": [
    "r = np.log(pr1/pr0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 431,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.log((y.items==positive).mean() / (y.items==negative).mean())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 432,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.994341, 1.088542, 1.      , 1.088542, ..., 0.544271, 0.544271, 0.544271, 0.544271])"
      ]
     },
     "execution_count": 432,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.exp(r)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here we fit regularized logistic regression where the features are the trigrams' log-count ratios."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 433,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.835"
      ]
     },
     "execution_count": 433,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_nb = xx.multiply(r)\n",
    "m = LogisticRegression(dual=True, C=0.1)\n",
    "m.fit(x_nb, y.items);\n",
    "\n",
    "val_x_nb = val_x.multiply(r)\n",
    "preds = m.predict(val_x_nb)\n",
    "(preds.T==valid_labels).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Baselines and Bigrams: Simple, Good Sentiment and Topic Classification. Sida Wang and Christopher D. Manning [pdf](https://www.aclweb.org/anthology/P12-2018)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
